你的位置:首页 > Java教程

[Java教程]文件传输基础——Java IO流


一、文件的编码

 1 package com.study.io; 2  3  4 /** 5  * 测试文件编码 6 */ 7 public class EncodeDemo { 8  9   /**10    * @param args11    * @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,如果不是目录或者目录不存在返回false22     System.out.println(file.isDirectory());23     //判断是否是一个文件isFile24     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 dir14    * @throws IOException15   */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对象的API29     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文件的模型:

运行结果:

01612[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

四、字节流(FileInputStream、FileOutputStream)

IO流可分为输入流和输出流。

这里又可分为字节流和字符流。

 代码示例:

 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 srcFile120    * @param destFile121    * @throws IOException122   */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 srcFile144    * @param destFile145    * @throws IOException146   */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();     }  }}

五、字符流

 

 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) 

❤ 字符流的过滤器

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

示例:

 注意: