- IO流整体架构图(简版)
-
IO流详解
-
基础流
- Reader
- Writer
- InputStream
- OutputStream
这几种是IO流的抽象父类,具体要操作的对象放到抽象父类的前面,比如要操作文件,就是FileInputStream、和FileReader。
其中FileInputStream和FileReader的区别是前者是读取字节,每八个比特为一个字节,然后一个字节一个字节的读取,而字符流则是根据编码集来就决定的,比如ascii码中是一个字节一个字节读取的。ANSI中文是读取两个字节。Unicode中中文是读取是那个字节。
所以按照这种规定,就保证了如果要读取文件中的中文就必须使用FileReader,不然这样就会导致读取到乱码。具体使用方法:
FileInputStream fis = new FileInputStream("abd/d.txt"); FileReader fr = new FileReader("abc/d.txt"); int b = -1; // 逐字节读取 while((b = fis.read()) != -1) { System.out.println((char) b); } // 根据中文和英文来逐字读取 int c = -1; while ((c = fr.read()) != -1) { System.out.println((char) c); } // 根据数组来读取 byte[] bytes = new byte[15]; int len; // 这里也可以换成fr来读取 while ((len = fis.read(bytes)) != -1) { System.out.println(new String(bytes)); }
💡 TIP1、java中表示文件路径用“\”,来表示,但是jvm底层转化了/,可以用其来转化,所以为了统一标准,均使用 / 来表示
💡 TIPS、文件的canonical的方式是除去路径中的…/和.,防止文件路径中的。
💡 TIP3、字符集最开始是ASCII码,用一个字节表示,所以可以表示128个字符,对于英文来说够用了,但是中文来说就会出现乱码。 所以为了适配中文、韩文、日文,退出了ANSI,其中包括GBK(简中)、BIG5(繁中)、EUC-KR(韩文)、shift-JS(日文),其中用两个字节表示一个字符。 最后为了适配所有地区的文字,开始出现Unicode,包含了大多数南美、非洲的国家,其中最常见的转化规则为utf-8,兼容ASCII,中文用三个字符表示。
💡 TIP4、字符流的底层为一个长度为8192的字节数组,每次读取尽量读满。
-
高级流
- 1、缓冲流,底层为一个长度为8192的字符数组,为了减少与硬盘的读取次数,增加速度,但是因为字符流本身就有缓冲数组,所以对于字符流来说,缓冲数组增加的速度不大。(主要用于复制文件,达到高速度),
FileInputStream fis1 = new FileInputStream("abc/t.txt"); BufferedInputStream bis = new BufferedInputStream(fis1); FileOutputStream fos = new FileOutputStream("abc/dd.txt"); BufferedOutputStream bos = new BufferedOutputStream(fos); int d while((d = bis.read()) != -1) { bos.write(d); } bis.close(); bos.close();
-
2、转化流
InputStreamReader:将输入字节流转化为字符
OutputStreamWriter:将输入字字节流转位为输出字符流
-
3、打印流(只有输出)
PrintStream(System.out,这是jvm自带的答应流):
printWriter()
-
4、解压缩流、压缩流
ZipInputStream ZipOutputStream
解压缩本质:把ZipEntry的对象下的每个对象copy到目标目录下面。
// 读取到entry,从压缩文件中读取。 ZipEntry nextEntry = inputStream.getNextEntry(); //不为空进入循环 while (nextEntry != null) { String name = nextEntry.getName(); File file = new File(outPath+name); //如果是目录,创建目录 if (name.endsWith("/")) { file.mkdir(); } else { //文件则写入具体的路径中 FileOutputStream fileOutputStream = new FileOutputStream(file); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream); int n; byte[] bytes = new byte[1024]; while ((n = inputStream.read(bytes)) != -1) { bufferedOutputStream.write(bytes, 0, n); } //关闭流 bufferedOutputStream.close(); fileOutputStream.close(); } //关闭当前布姆 inputStream.closeEntry(); //读取下一个目录,作为循环条件 nextEntry = inputStream.getNextEntry(); }
压缩的本质:将每个文件创建为ZipEntry对象
File file = new File("d:" + File.separator + "liuxun") ; // 定义要压缩的文件夹 File zipFile = new File("d:" + File.separator + "liuxundir.zip") ; // 定义压缩文件名称 InputStream input = null ; // 定义文件输入流 ZipOutputStream zipOut = null ; // 声明压缩流对象 zipOut = new ZipOutputStream(new FileOutputStream(zipFile)) ; zipOut.setComment("liuxunTEST") ; // 设置注释 int temp = 0 ; if(file.isDirectory()){ // 判断是否是文件夹 File lists[] = file.listFiles() ; // 列出全部文件 for(int i=0;i<lists.length;i++){ input = new FileInputStream(lists[i]) ; // 定义文件的输入流 zipOut.putNextEntry(new ZipEntry(file.getName() +File.separator+lists[i].getName())) ; // 设置ZipEntry对象 while((temp=input.read())!=-1){ // 读取内容 zipOut.write(temp) ; // 压缩输出 } input.close() ; // 关闭输入流 } } zipOut.close() ; // 关闭输出流
-
序列化流和反序列化流
将serializable的类持久化。
ObjectInputStream
ObjectOutputStream
💡 两个工具Commons-io和hutools
-