• 文件传输基础——Java IO流


    一、文件的编码

     1 package com.study.io;
     2 
     3 
     4 /**
     5  * 测试文件编码
     6  */
     7 public class EncodeDemo {
     8 
     9     /**
    10      * @param args
    11      * @throws Exception 
    12      */
    13     public static void main(String[] args) throws Exception {
    14         String s="好好学习ABC";
    15         byte[] bytes1=s.getBytes();//这是把字符串转换成字符数组,转换成的字节序列用的是项目默认的编码(这里为UTF-8)
    16         for (byte b : bytes1) {
    17             //把字节(转换成了int)以16进制的方式显示
    18             System.out.print(Integer.toHexString(b & 0xff)+" ");//& 0xff是为了把前面的24个0去掉只留下后八位
    19         }
    20         System.out.println();
    21         /*utf-8编码中中文占用3个字节,英文占用1个字节*/
    22         byte[] bytes2 = s.getBytes("utf-8");//这里会有异常展示,我们就throw这个异常
    23         for (byte b : bytes2) {
    24             System.out.print(Integer.toHexString(b & 0xff)+" ");
    25         }
    26         System.out.println();
    27         /*gbk编码中文占用2个字节,英文占用1个字节*/
    28         byte[] bytes3 = s.getBytes("gbk");//这里会有异常展示,我们就throw这个异常
    29         for (byte b : bytes3) {
    30             System.out.print(Integer.toHexString(b & 0xff)+" ");
    31         }
    32         
    33         System.out.println();
    34         /*utf-16be编码中文占用2个字节,英文占用2个字节*/
    35         byte[] bytes4 = s.getBytes("utf-16be");//这里会有异常展示,我们就throw这个异常
    36         for (byte b : bytes4) {
    37             System.out.print(Integer.toHexString(b & 0xff)+" ");
    38         }
    39         
    40         System.out.println();
    41         /*当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码*/
    42         String str1=new String(bytes4);//这时会使用项目默认的编码来转换,可能出现乱码
    43         System.out.println(str1);
    44         //要使用字节序列的编码来进行转换
    45         String str2=new String(bytes4,"utf-16be");
    46         System.out.println(str2);
    47     }
    48 }

    分析:

    * 1. “& 0xff”的解释:
    * 0xFF表示的是16进制(十进制是255),表示为二进制就是“11111111”。
    * 那么&符表示的是按位数进行与(同为1的时候返回1,否则返回0)

    * 2.字节byte与int类型转换:
    * Integer.toHexString(b & 0xff)这里先把byte类型的b和0xff进行了运算,然后Integer.toHexString取得了十六进制字符串
    * 可以看出b & 0xFF运算后得出的仍然是个int,那么为何要和 0xFF进行与运算呢?直接 Integer.toHexString(b);,将byte强转为int不行吗?答案是不行的.
    * 其原因在于:1.byte的大小为8bits而int的大小为32bits;2.java的二进制采用的是补码形式
    * Integer.toHexString的参数是int,如果不进行&0xff,那么当一个byte会转换成int时,由于int是32位,而byte只有8位这时会进行补位。。。。。。
    * 所以,一个byte跟0xff相与会先将那个byte转化成整形运算,这样,结果中的高的24个比特就总会被清0,于是结果总是我们想要的。

    * 3.utf-8编码:中文占用3个字节,英文占用1个字节
    * gbk编码:中文占用2个字节,英文占用1个字节
    * Java采用双字节编码(就是Java中的一个字符占两个字节)是utf-16be编码。中文占用2个字节,英文占用2个字节
    *
    * 4.当你的字节序列是某种编码时,这个时候想把字节序列变成字符串,也需要用这种编码方式,否则会出现乱码

    * 5.文本文件 就是字节序列。可以是任意编码的字节序列。
    * 如果我们在中文机器上直接创建文本文件,那么该文件只认识ANSI编码(例如直接在电脑中创建文本文件)

    二、File类的使用

     1 package com.study.io;
     2 
     3 import java.io.File;
     4 
     5 /**
     6  * File类的使用
     7  */
     8 public class FileDemo {
     9     /*java.iO.File类表示文件或目录
    10     File类只用于表示文件或目录的信息(名称,大小等),不能用于文件内容的访问。*/
    11     public static void main(String[] args) {
    12         File file=new File("D:\111");//创建文件对象时指定目录需要用双斜杠,因为“”是转义字符
    13         /*目录的中间的分隔符可以用双斜杠,也可以用反斜杠,也可以用File.separator设置分隔符*/
    14 //        File file1=new File("d:"+File.separator);
    15 //        System.out.println(file.exists());//exists()判断文件或文件夹是否存在
    16         if(!file.exists()){//如果文件不存在
    17             file.mkdir();//创建文件夹mkdir(),还有mkdirs()创建多级目录
    18         }else{
    19             file.delete();//删除文件或文件夹
    20         }
    21         //判断是否是一个目录isDirectory,如果是目录返回true,如果不是目录或者目录不存在返回false
    22         System.out.println(file.isDirectory());
    23         //判断是否是一个文件isFile
    24         System.out.println(file.isFile());
    25         
    26         File file2=new File("D:\222","123.txt");
    27         //常用API:
    28         System.out.println(file);//打印的是file.toString()的内容
    29         System.out.println(file.getAbsolutePath());//获取绝对路径
    30         System.out.println(file.getName());//获取文件名称
    31         System.out.println(file2.getName());
    32         System.out.println(file.getParent());//获取父级绝对路径
    33         System.out.println(file2.getParentFile().getAbsolutePath());
    34     }
    35 }

    运行结果:

    说明:

    java.iO.File类表示文件或目录
    File类只用于表示文件或目录的信息(名称,大小等),不能用于文件内容的访问。
    常用的API:
    1.创建File对象:File file=new File(String path);注意:File.seperater();获取系统分隔符,如:“”.
    2.boolean file.exists();是否存在.
    3.file.mkdir();或者file.mkdirs();创建目录或多级目录。
    4.file.isDirectory()判断是否是目录
    file.isFile()判断是否是文件。
    5.file.delete();删除文件或目录。
    6.file.createNewFile();创建新文件。
    7.file.getName()获取文件名称或目录绝对路径。
    8.file.getAbsolutePath()获取绝对路径。
    9.file.getParent();获取父级绝对路径。

     ❤❤1、遍历目录

     1 package com.study.io;
     2 
     3 import java.io.File;
     4 import java.io.IOException;
     5 
     6 /**
     7  * File工具类
     8  * 列出File类的常用操作,比如:过滤、遍历等操作
     9  */
    10 public class FileUtils {
    11     /**
    12      * 列出指定目录下(包括其子目录)的所有文件
    13      * @param dir
    14      * @throws IOException
    15      */
    16     public static void listDirectory(File dir) throws IOException{
    17         if(!dir.exists()){//exists()方法用于判断文件或目录是否存在
    18             throw new IllegalArgumentException("目录:"+dir+"不存在");
    19         }
    20         if(!dir.isDirectory()){//isDirectory()方法用于判断File类的对象是否是目录
    21             throw new IllegalArgumentException(dir+"不是目录");
    22         }
    23         /*String[] fileNames = dir.list();//list()方法用于列出当前目录下的子目录和文件(直接是子目录的名称,不包含子目录下的内容),返回的是字符串数组
    24         for (String string : fileNames) {
    25             System.out.println(string);
    26         }*/
    27         
    28         //如果要遍历子目录下的内容就需要构造成File对象做递归操作,File提供了直接返回File对象的API
    29         File[] listFiles = dir.listFiles();//返回的是直接子目录(文件)的抽象
    30         if(listFiles !=null && listFiles.length >0){
    31             for (File file : listFiles) {
    32                 /*System.out.println(file);*/
    33                 if(file.isDirectory()){
    34                     //递归
    35                     listDirectory(file);
    36                 }else{
    37                     System.out.println(file);
    38                 }
    39             }
    40         }
    41     }
    42 }

    测试类:

    1 public class FileUtilsTest1 {
    2     public static void main(String[] args) throws IOException {
    3         FileUtils.listDirectory(new File("D:\ioStudy"));
    4     }
    5 }

    运行结果:

    三、RandomAccessFile类的使用

    RandomAccessFile:java提供的对文件内容的访问,既可以读文件,也可以写文件。
    RandomAccessFile支持随机访问文件,可以访问文件的任意位置。

    注意 Java文件的模型:

    示例代码:

     1 package com.study.io;
     2 
     3 import java.io.File;
     4 import java.io.IOException;
     5 import java.io.RandomAccessFile;
     6 import java.util.Arrays;
     7 
     8 
     9 /**
    10  * RandomAccessFile
    11  */
    12 public class RandomAccessFileDemo {
    13     public static void main(String[] args) throws IOException{
    14         File demo = new File("demo");
    15         if(!demo.exists()){
    16          demo.mkdir();
    17         }
    18         File file = new File(demo,"raf.dat");
    19         if(!file.exists()){
    20          file.createNewFile();
    21         }
    22         
    23         RandomAccessFile raf = new RandomAccessFile(file, "rw");
    24         //指针的位置
    25         System.out.println(raf.getFilePointer());
    26         
    27         raf.write('A');//只写了一个字节
    28         System.out.println(raf.getFilePointer());
    29         raf.write('B');
    30         
    31         int i = 0x7fffffff;
    32         //用write方法每次只能写一个字节,如果要把i写进去就得写4次
    33         raf.write(i >>> 24);//高8位
    34         raf.write(i >>> 16);
    35         raf.write(i >>> 8);
    36         raf.write(i);
    37         System.out.println(raf.getFilePointer());
    38         
    39         //可以直接写一个int
    40         raf.writeInt(i);
    41         
    42         String s = "中";
    43         byte[] gbk = s.getBytes("gbk");
    44         raf.write(gbk);
    45         System.out.println(raf.length());
    46         
    47         //读文件,必须把指针移到头部
    48         raf.seek(0);
    49         //一次性读取,把文件中的内容都读到字节数组中
    50         byte[] buf = new byte[(int)raf.length()];
    51         raf.read(buf);
    52         
    53         System.out.println(Arrays.toString(buf));
    54            for (byte b : buf) {
    55          System.out.println(Integer.toHexString(b & 0xff)+" ");
    56         }
    57            raf.close();
    58     }
    59 }

    运行结果:

    0
    1
    6
    12
    [65, 66, 127, -1, -1, -1, 127, -1, -1, -1, -42, -48]
    41 
    42 
    7f 
    ff 
    ff 
    ff 
    7f 
    ff 
    ff 
    ff 
    d6 
    d0 
    View Code

    四、字节流(InputStream、OutputStream)

    Java流操作有关的类或接口:

    Java流类图结构:

    IO流的分类

    • 根据处理数据类型的不同分为:字符流和字节流
    • 根据数据流向不同分为:输入流和输出流

    字符流和字节流

    字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 字节流和字符流的区别:

    • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
    • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

    结论:只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。

    输入流和输出流

    对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。 

     代码示例:

      1 package com.study.io;
      2 
      3 import java.io.BufferedInputStream;
      4 import java.io.BufferedOutputStream;
      5 import java.io.File;
      6 import java.io.FileInputStream;
      7 import java.io.FileOutputStream;
      8 import java.io.IOException;
      9 
     10 /**
     11  * IO工具类
     12  * ❤文件输入输出流:
     13  * FileInputStream-->具体实现了在文件上读取数据
     14  * FileOutputStream-->实现了向文件中写出byte数据的方法
     15  * ❤数据输入输出流:
     16  * DataOutputStream / DataInputStream:对"流"功能的扩展,可以更加方面的读取int,long,字符等类型数据
     17  * DataOutputStream  writeInt()/writeDouble()/writeUTF()
     18  * ❤字节缓冲流:
     19  * BufferedInputStream & BufferedOutputStream
     20  * 这两个流类位IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能 
     21  * 比如:从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
     22      FileOutputStream--->write()方法相当于一滴一滴地把水“转移”过去
     23      DataOutputStream-->writeXxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
     24      BufferedOutputStream--->write方法更方便,相当于一瓢一瓢先放入桶中(即缓存区),再从桶中倒入到另一个缸中,性能提高了
     25  */
     26 public class IOUtil {
     27     
     28     /**
     29      * 读取指定文件内容,按照16进制输出到控制台
     30      * 并且每输出10个byte换行
     31      * @param fileName
     32      * 单字节读取不适合大文件,大文件效率很低
     33      */
     34     public static void printHex(String fileName)throws IOException{
     35         //把文件作为字节流进行都操作
     36         FileInputStream in=new FileInputStream(fileName);
     37         int b;
     38         int i=1;
     39         while((b=in.read())!=-1){
     40             /* 0xff换成2进制就是8个1,这样与的话,其实就是取到了字符的低8位。 
     41              * oxf就是15, 小于15的数会转换成一个16进制数,
     42              * 你的代码里希望是固定的两个16进制数,所以当只会产生一个时要加个0*/
     43             if(b <= 0xf){
     44                 //单位数前面补0
     45                 System.out.print("0");
     46             }
     47             //Integer.toHexString(b)将整型b转换为16进制表示的字符串
     48             System.out.print(Integer.toHexString(b)+" ");
     49             if(i++%10==0){
     50                 System.out.println();
     51             }
     52         }
     53         in.close();//文件读写完成以后一定要关闭
     54     }
     55 
     56     /**
     57      * 批量读取,对大文件而言效率高,也是我们最常用的读文件的方式
     58      * @param fileName
     59      * @throws IOException
     60      */
     61     public static void printHexByByteArray(String fileName)throws IOException{
     62         FileInputStream in = new FileInputStream(fileName);
     63         byte[] buf = new byte[8 * 1024];
     64         /*从in中批量读取字节,放入到buf这个字节数组中,
     65          * 从第0个位置开始放,最多放buf.length个 
     66          * 返回的是读到的字节的个数
     67          */
     68         /*int bytes = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
     69      int j = 1; 
     70      for(int i = 0; i < bytes;i++){
     71       System.out.print(Integer.toHexString(buf[i] & 0xff)+"  ");
     72       if(j++%10==0){
     73        System.out.println();
     74       }
     75      }*/
     76         int bytes = 0;
     77         int j = 1;
     78         while((bytes = in.read(buf,0,buf.length))!=-1){
     79             for(int i = 0 ; i < bytes;i++){
     80                 System.out.print(Integer.toHexString(buf[i] & 0xff)+"  ");
     81                 /**
     82                  * & 0xff:byte类型8位,int类型32位,为了避免数据转换错误,通过&0xff将高24位清零
     83                  */
     84                 if(j++%10==0){
     85                     System.out.println();
     86                 }
     87             }
     88         }
     89         in.close();
     90     }
     91     
     92     /**
     93      * 文件拷贝,字节批量读取
     94      * @param srcFile
     95      * @param destFile
     96      * @throws IOException
     97      */
     98     public static void copyFile(File srcFile, File destFile) throws IOException {
     99         if (!srcFile.exists()) {
    100             throw new IllegalArgumentException("文件:" + srcFile + "不存在");
    101         }
    102         if (!srcFile.isFile()) {
    103             throw new IllegalArgumentException(srcFile + "不是文件");
    104         }
    105         FileInputStream in = new FileInputStream(srcFile);
    106         FileOutputStream out = new FileOutputStream(destFile);//文件不存在时,会直接创建;如果存在,删除后建
    107         byte[] buf = new byte[8 * 1024];//批量读写
    108         int b;
    109         while ((b = in.read(buf, 0, buf.length)) != -1) {//read(buf,0,buf.length)带参数的read返回的是字节的总长度;当全部读完后返回的是-1;
    110             out.write(buf, 0, b);
    111             out.flush();// 最好加上
    112         }
    113         in.close();
    114         out.close();
    115     }
    116     
    117     /**
    118      * 进行文件的拷贝,利用带缓冲的字节流
    119      * @param srcFile
    120      * @param destFile
    121      * @throws IOException
    122      */
    123     public static void copyFileByBuffer(File srcFile,File destFile)throws IOException{
    124         if(!srcFile.exists()){
    125             throw new IllegalArgumentException("文件:"+srcFile+"不存在");
    126         }
    127         if(!srcFile.isFile()){
    128             throw new IllegalArgumentException(srcFile+"不是文件");
    129         }
    130         BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
    131         BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
    132         int c ;
    133         while((c = bis.read())!=-1){
    134             bos.write(c);
    135             bos.flush();//刷新缓冲区
    136         }
    137         bis.close();
    138         bos.close();
    139     }
    140     
    141     /**
    142      * 单字节,不带缓冲进行文件拷贝
    143      * @param srcFile
    144      * @param destFile
    145      * @throws IOException
    146      */
    147     public static void copyFileByByte(File srcFile,File destFile)throws IOException{
    148         if(!srcFile.exists()){
    149             throw new IllegalArgumentException("文件:"+srcFile+"不存在");
    150         }
    151         if(!srcFile.isFile()){
    152             throw new IllegalArgumentException(srcFile+"不是文件");
    153         }
    154         FileInputStream in = new FileInputStream(srcFile);
    155         FileOutputStream out = new FileOutputStream(destFile);
    156         int c ;
    157         while((c = in.read())!=-1){//read()不带参数的read返回的是读到的字节内容;当全部读完后返回的都是是-1;
    158             out.write(c);
    159             out.flush();
    160         }
    161         in.close();
    162         out.close();
    163     }
    164 }

    测试类:

    package com.study.io;
    
    
    import java.io.File;
    import java.io.IOException;
    
    import org.junit.Test;
    
    public class IOUtilTest {
    
        @Test
        public void testPrintHex() {
            try {
                IOUtil.printHex("D:\Javaio\FileUtils.java");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        @Test
        public void testPrintHexByByteArray() {
            try {
                long start = System.currentTimeMillis();//当前时间与协调世界时 1970 年 1 月 1 日午夜之间的时间差(以毫秒为单位测量)
                //IOUtil.printHexByByteArray("e:\javaio\FileUtils.java");
                //IOUtil.printHex("e:\javaio\1.mp3");
                IOUtil.printHexByByteArray("e:\javaio\1.mp3");
                System.out.println();
                long end = System.currentTimeMillis();
                System.out.println(end - start);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
       @Test
       public void testCopyFile(){
           try {
               IOUtil.copyFile(new File("d:\javaio\1.txt"), new File("d:\javaio\1copy.txt"));
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
    
       @Test
       public void testCopyFileByBuffer(){
           try {
               long start = System.currentTimeMillis();
               /*IOUtil.copyFileByByte(new File("e:\javaio\1.mp3"), new File(
                 "e:\javaio\2.mp3"));*/  //两万多毫秒
               /*IOUtil.copyFileByBuffer(new File("e:\javaio\1.mp3"), new File(
                 "e:\javaio\3.mp3"));//一万多毫秒*/
               IOUtil.copyFile(new File("e:\javaio\1.mp3"), new File(
                 "e:\javaio\4.mp3"));//7毫秒
               long end = System.currentTimeMillis();
               System.out.println(end - start );
              } catch (IOException e) {
               e.printStackTrace();
              } 
       }
    }

    五、字符流(Reader、Writer)

     

     1 package com.study.io;
     2 
     3 import java.io.FileInputStream;
     4 import java.io.FileOutputStream;
     5 import java.io.IOException;
     6 import java.io.InputStreamReader;
     7 import java.io.OutputStreamWriter;
     8 
     9 public class IsrAndOswDemo {
    10     public static void main(String[] args)throws IOException {
    11         FileInputStream in = new FileInputStream("e:\javaio\utf8.txt");
    12         InputStreamReader isr = new InputStreamReader(in,"utf-8");//默认项目的编码,操作的时候,要写文件本身的编码格式
    13 
    14         FileOutputStream out = new FileOutputStream("e:\javaio\utf81.txt");
    15         OutputStreamWriter osw = new OutputStreamWriter(out,"utf-8");
    16         /*int c ;
    17   while((c = isr.read())!=-1){
    18    System.out.print((char)c);
    19   }*/
    20         char[] buffer = new char[8*1024];
    21         int c;
    22         /*批量读取,放入buffer这个字符数组,从第0个位置开始放置,最多放buffer.length个返回的是读到的字符的个数*/
    23         while(( c = isr.read(buffer,0,buffer.length))!=-1){
    24             String s = new String(buffer,0,c);
    25             System.out.print(s);
    26             osw.write(buffer,0,c);
    27             osw.flush();
    28         }
    29         isr.close();
    30         osw.close();
    31 
    32     }
    33 
    34 }

     ❤ 字符流之文件读写流(FileReader/FileWriter) 

    ❤ 字符流的过滤器

    六、对象的序列化和反序列化

    示例:

     注意:

     序列化拓展文章:

    深入分析Java的序列化与反序列化

    Java 序列化的高级认识(转载)

  • 相关阅读:
    Jmeter混合场景压力测试
    数据驱动DDT(Data-Driven Tests):测试数据的参数化
    运用TextSuite和TestRunner运行测试脚本
    Test Fixture框架结构
    解决appium-doctor报各种 cannot be found问题
    搭建python+appium环境的时候遇到 'could not find adb.exe!'的问题
    Python appium搭建app自动化测试环境
    夜神模拟器查看APP的activity等信息
    [leetcode 23]Merge k Sorted Lists
    [leetcode 22]generate parentheses
  • 原文地址:https://www.cnblogs.com/Qian123/p/5632028.html
Copyright © 2020-2023  润新知