尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Java IO流(超详细!!!)

Java IO流(超详细!!!) Java IO流文章目录Java IO流1.文件相关基础普及1.1 常用文件操作1.3 目录的操作和文件删除2.IO流原理及流的分类2.1 字节流2.1.1 InputStream字节输入流2.1.2 OutputStream2.2 字符流2.2.1 Reader2.2.1 Writer2.3 节点流和处理流2.3.1节点流2.3.2 处理流2.3.2.1 处理流设计模式2.3.2.2 缓冲流2.3.2.2.1 字节缓冲输入流2.3.2.2.1 字符缓冲流2.3.3 对象处理流2.3.3.1序列化与反序列化2.3.3.1 OjectOutputStream与OjectOutputStream2.3.3.2 对象处理流使用细节2.4 转换流2.4.1 InputStreamReader :2.4.1 OutputStreamWriter1.文件相关基础普及创建文件对象相关构造器和相关方法:new File(String pathname)//根据路径构建一个File对象new File(File parent, String child)/根据父目录文件子路径构建new File(String parent,String child)//根据父目录子路径构建createNewFile(); 创建新文件接下来我们通过一个简单的例子实现文件创建packageio;importjava.io.File;importjava.io.IOException;publicclassioTest01{publicstaticvoidmain(String[]args){StringfilePath/Users/Zhuanz1/Desktop/大三下Java就业/java网络/netTest/src/io/test.txt;//文件具体路径FilefilenewFile(filePath);try{file.createNewFile();System.out.println(创建成功);}catch(IOExceptione){e.printStackTrace();}}}在这个例子中我们使用绝对路径/Users/Zhuanz1/Desktop/大三下Java就业/java网络/netTest/src/io/test.txt将文件创建出来。1.1 常用文件操作文件操作中常用的关键词有以下几个getName,getAbsolutePath,getParent,length,exists,isFile,isDirectory。包含获取文件名获取文件的绝对路径文件的父目录长度等。1.3 目录的操作和文件删除mkdir创建一级目录、mkdirs创建多级目录、delete删除空目录或文件文件创建案例packagecom.example;importjava.io.File;publicclassFileTest01{publicstaticvoidmain(String[]args){try{FilefilenewFile(src/main/resources/test);file.mkdir();System.out.println(创建成功);}catch(Exceptione){e.printStackTrace();};}}在此案例中我们根据指定创建了一个test文件夹。2.IO流原理及流的分类IO 即Input/Output输入和输出。数据输入到计算机内存的过程即输入反之输出到外部存储比如数据库文件远程主机的过程即输出。数据传输过程类似于水流因此称为 IO 流。IO 流在 Java 中分为输入流和输出流而根据数据的处理方式又分为字节流和字符流。Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的。InputStream/Reader: 所有的输入流的基类前者是字节输入流后者是字符输入流。OutputStream/Writer: 所有输出流的基类前者是字节输出流后者是字符输出流。2.1 字节流2.1.1 InputStream字节输入流InputStream用于从源头通常是文件读取数据字节信息到内存中java.io.InputStream抽象类是所有字节输入流的父类。packagecom.example;importjava.io.*;importjava.nio.charset.StandardCharsets;importjava.util.Scanner;publicclassInputStreamTest01{publicstaticvoidmain(String[]args){StringfileAddresssrc/main/resources/file1.txt;FilefilenewFile(fileAddress);// 确保父目录存在FileparentDirfile.getParentFile();if(parentDir!null!parentDir.exists()){parentDir.mkdirs();// 创建必要的父目录System.out.println(已创建目录parentDir.getPath());}// 使用 try-with-resources 管理资源try(ScannerscannernewScanner(System.in);OutputStreamoutputStreamnewFileOutputStream(file);InputStreaminputStreamnewFileInputStream(file)){// 检查文件是否存在if(file.exists()){System.out.println(文件已经存在);}else{System.out.println(文件创建成功);}// 获取用户输入并写入文件System.out.println(你可以记录的所感所想);Stringrecordscanner.nextLine();outputStream.write(record.getBytes(StandardCharsets.UTF_8));// 指定 UTF-8 编码outputStream.flush();// 确保数据写入文件// 读取文件内容并输出byte[]buffernewbyte[1024];intlen;while((leninputStream.read(buffer))!-1){System.out.print(newString(buffer,0,len,StandardCharsets.UTF_8));}}catch(IOExceptione){System.err.println(操作文件时发生错误e.getMessage());e.printStackTrace();}}}这个 Java 程序的功能是通过用户输入记录文本到文件并读取文件内容显示出来。在资源管理中使用 try-with-resources 语句初始化 Scanner用于用户输入、FileOutputStream用于写文件和 FileInputStream用于读文件确保资源自动关闭。实现文件成功创建并且将我们的输入的字段输出出来。不过一般我们是不会直接单独使用FileInputStream通常会配合BufferedInputStream字节缓冲输入流后文会讲到来使用。2.1.2 OutputStreamOutputStream用于将数据字节信息写入到目的地通常是文件java.io.OutputStream抽象类是所有字节输出流的父类。通过这个例子使用OutputStream在文件“file1.txt中写入“i love you so”若文件不存在则创建packagecom.example;importjava.io.FileOutputStream;importjava.io.IOException;publicclassOutputSteamTest01{publicstaticvoidmain(String[]args)throwsIOException{StringfileAdresssrc/main/resources/file1.txt;//操作目标文件路径intlength0;byte[]bufnewbyte[1024];//缓冲区FileOutputStreamfileInputStreamnull;try{fileInputStreamnewFileOutputStream(fileAdress,true);//读取文件 加了true 实现文件不覆盖写入Stringstri love you so;fileInputStream.write(str.getBytes());//getBytes()String方法有将str转为byte类型System.out.println(写入成功);}catch(Exceptione){e.printStackTrace();}finally{fileInputStream.close();}}}结果如下成功写入类似于FileInputStreamFileOutputStream通常也会配合BufferedOutputStream字节缓冲输出流后文会讲到来使用。FileOutputStreamfileOutputStreamnewFileOutputStream(output.txt);BufferedOutputStreambosnewBufferedOutputStream(fileOutputStream)2.2 字符流不管是文件读写还是网络发送接收信息的最小存储单元都是字节。那为什么 I/O 流操作要分为字节流操作和字符流操作呢个人认为主要有两点原因字符流是由 Java 虚拟机将字节转换得到的这个过程还算是比较耗时。如果我们不知道编码类型就很容易出现乱码问题。乱码问题这个很容易就可以复现我们只需要将上面提到的FileInputStream代码示例中的input.txt文件内容改为中文即可原代码不需要改动。可以很明显地看到读取出来的内容已经变成了乱码。因此I/O 流就干脆提供了一个直接操作字符的接口方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好如果涉及到字符的话使用字符流比较好。字符流默认采用的是Unicode编码我们可以通过构造方法自定义编码。Unicode 本身只是一种字符集它为每个字符分配一个唯一的数字编号并没有规定具体的存储方式。UTF-8、UTF-16、UTF-32 都是 Unicode 的编码方式它们使用不同的字节数来表示 Unicode 字符。例如UTF-8 :英文占 1 字节中文占 3 字节。2.2.1 ReaderReader用于从源头通常是文件读取数据字符信息到内存中java.io.Reader抽象类是所有字符输入流的父类。Reader用于读取文本InputStream用于读取原始字节。Reader常用方法read(): 从输入流读取一个字符。read(char[] cbuf): 从输入流中读取一些字符并将它们存储到字符数组cbuf中等价于read(cbuf, 0, cbuf.length)。read(char[] cbuf, int off, int len)在read(char[] cbuf)方法的基础上增加了off参数偏移量和len参数要读取的最大字符数。skip(long n)忽略输入流中的 n 个字符 ,返回实际忽略的字符数。close(): 关闭输入流并释放相关的系统资源。InputStreamReader是字节流转换为字符流的桥梁其子类FileReader是基于该基础上的封装可以直接操作字符文件。FileReader代码示例try(FileReaderfileReadernewFileReader(input.txt);){intcontent;longskipfileReader.skip(3);System.out.println(The actual number of bytes skipped:skip);System.out.print(The content read from file:);while((contentfileReader.read())!-1){System.out.print((char)content);}}catch(IOExceptione){e.printStackTrace();}输出The actual number of bytes skipped:3 The content read from file:我是Guide。2.2.1 WriterWriter用于将数据字符信息写入到目的地通常是文件java.io.Writer抽象类是所有字符输出流的父类。Writer常用方法write(int c): 写入单个字符。write(char[] cbuf)写入字符数组cbuf等价于write(cbuf, 0, cbuf.length)。write(char[] cbuf, int off, int len)在write(char[] cbuf)方法的基础上增加了off参数偏移量和len参数要读取的最大字符数。write(String str)写入字符串等价于write(str, 0, str.length())。write(String str, int off, int len)在write(String str)方法的基础上增加了off参数偏移量和len参数要读取的最大字符数。append(CharSequence csq)将指定的字符序列附加到指定的Writer对象并返回该Writer对象。append(char c)将指定的字符附加到指定的Writer对象并返回该Writer对象。flush()刷新此输出流并强制写出所有缓冲的输出字符。close():关闭输出流释放相关的系统资源。FileWriter代码示例try(WriteroutputnewFileWriter(output.txt)){output.write(你好我是Guide。);}catch(IOExceptione){e.printStackTrace();}2.3 节点流和处理流2.3.1节点流1.节点流可以从一个特定的数据源读写数据如FileReader、FileWriter如上图就是javaIO中所有的的节点流与处理流包括字节和字符类型。例如下图当我们需要操作一个文件时那么我们就可以通过节点流利用file文件类型使用fileReader实现文件的读取。同理当我们需要操作别的类型时就调用别的类型的节点流即可实现不用数据类型的内容读取。例如我们在上一章节使用过的一个例子我们需要通过操作目标文件实现写入。我们使用了FileOutputStream节点流处理文件类型数据实现文件读取功能。package com.example; import java.io.FileOutputStream; import java.io.IOException; public class OutputSteamTest01 { public static void main(String[] args) throws IOException { String fileAdress src/main/resources/file1.txt;//操作目标文件路径 int length 0; byte[] buf new byte[1024];//缓冲区 FileOutputStream fileInputStream null; try { fileInputStream new FileOutputStream(fileAdress,true);//读取文件 加了true 实现文件不覆盖写入 String str i love you so; fileInputStream.write(str.getBytes());//getBytes()String方法有将str转为byte类型 System.out.println(写入成功); } catch (Exception e) { e.printStackTrace(); }finally { fileInputStream.close(); } } }由此我们可以得出针对不同数据源我们就选择相对应的节点流。直接操作数据源这种方式也相对底层无法对数据源进行修改删除操作。只能实现简单读取功能。2.3.2 处理流2.3.2.1 处理流设计模式2.处理流包装流是“连接”在已存在的流节点流或处理流之上为程序提供更为强大的读写能力如BufferedReader、BufferedWriter简单来说就无须管文本输入输出类型直接操作数据源。例如我们后面会介绍到的BufferWriter,我们可以通过BufferWriter操作各种数据类型。更加灵活2.3.2.2 缓冲流2.3.2.2.1 字节缓冲输入流IO 操作是很消耗性能的缓冲流将数据加载至缓冲区一次性读取/写入多个字节从而避免频繁的 IO 操作提高流的传输效率。字节缓冲流这里采用了装饰器模式来增强InputStream和OutputStream子类对象的功能。举个例子我们可以通过BufferedInputStream字节缓冲输入流来增强FileInputStream的功能。只// 新建一个 BufferedInputStream 对象BufferedInputStreambufferedInputStreamnewBufferedInputStream(newFileInputStream(input.txt));字节流和字节缓冲流的性能差别主要体现在我们使用两者的时候都是调用write(int b)和read()这两个一次只读取一个字节的方法的时候。由于字节缓冲流内部有缓冲区字节数组因此字节缓冲流会先将读取到的字节存放在缓存区大幅减少 IO 次数提高读取效率。我使用write(int b)和read()方法分别通过字节流和字节缓冲流复制一个524.9 mb的 PDF 文件耗时对比如下使用缓冲流复制PDF文件总耗时:15428 毫秒 使用普通字节流复制PDF文件总耗时:2555062 毫秒两者耗时差别非常大缓冲流耗费的时间是字节流的 1/165。测试代码如下:Testvoidcopy_pdf_to_another_pdf_buffer_stream(){// 记录开始时间longstartSystem.currentTimeMillis();try(BufferedInputStreambisnewBufferedInputStream(newFileInputStream(深入理解计算机操作系统.pdf));BufferedOutputStreambosnewBufferedOutputStream(newFileOutputStream(深入理解计算机操作系统-副本.pdf))){intcontent;while((contentbis.read())!-1){bos.write(content);}}catch(IOExceptione){e.printStackTrace();}// 记录结束时间longendSystem.currentTimeMillis();System.out.println(使用缓冲流复制PDF文件总耗时:(end-start) 毫秒);}Testvoidcopy_pdf_to_another_pdf_stream(){// 记录开始时间longstartSystem.currentTimeMillis();try(FileInputStreamfisnewFileInputStream(深入理解计算机操作系统.pdf);FileOutputStreamfosnewFileOutputStream(深入理解计算机操作系统-副本.pdf)){intcontent;while((contentfis.read())!-1){fos.write(content);}}catch(IOExceptione){e.printStackTrace();}// 记录结束时间longendSystem.currentTimeMillis();System.out.println(使用普通流复制PDF文件总耗时:(end-start) 毫秒);}在结束时我们只需要关闭外层处理流即可底层会去关闭节点流。2.3.2.2.1 字符缓冲流BufferedReader字符缓冲输入流和BufferedWriter字符缓冲输出流类似于BufferedInputStream字节缓冲输入流和BufferedOutputStream字节缓冲输入流内部都维护了一个字节数组作为缓冲区。不过前者主要是用来操作字符信息。2.3.3 对象处理流既可以保存数据的值也可以保存数据的数据类型使得数据被保存到文件中后还能够从文件中恢复。作用 :eg1 : 一个基本类型数据 int i 5; 对象处理流可以将i变量的值5和它的数据类型int都保存到文件中eg2 : 一个引用类型数据 Cat cat new Cat(bubble, 5, white);对象处理流可以将cat变量的值String-bubble, int-5, String-white都保存下来还可以记录下它的数据类型是Cat类型。2.3.3.1序列化与反序列化序列化——*保存数据的值和数据类型到文件中*。反序列化——*将文件中保存的数据包含值和数据类型重新恢复成数据本身*。​ 如下图所示 :2.3.3.1 OjectOutputStream与OjectOutputStreamObjectOutputStream继承自OutputStream类它可以实现数据的序列化。ObjectOutputStream类同样使用了“修饰器模式”即该类中有一个OutputStream的引用变量存在于OutputStream类的静态内部类BlockDataOutputStream中。ObjectInputStream类继承自InputStream类它可以实现数据的反序列化。ObjectInputStream类同样使用了“修饰器模式”即该类中有一个InputStream的引用变量存在于InputStream类中的静态内部类PeekInputStream中)。2.3.3.2 对象处理流使用细节关于序列化的一些细节1° 序列化或者反序列化的对象必须实现实现Serializable接口并且序列化和反序列化时写入数据与读取数据的顺序必须一致。 2° 序列化类中建议添加serialVersionUID可以提高版本的兼容性。 3° 序列化对象时默认要将里面所有属性都进行序列化但不包括static和transient修饰的成员。 4° 序列化对象时要求里面的属性的类型也要实现序列化接口。eg : String, Integer等类已实现了序列化 5° 序列化具备可继承性即如果某个类实现了序列化默认其所有子类也实现了序列化。eg : Number --- Serializable)2.4 转换流若在txt文件中出现中文并且该文件没有使用UTF-8形式编码在使用IO流读取文件时就会出现乱码问题。转换流可以解决乱码问题转换流可以将字节流转成字符流同时指定读取文件时按照怎样的编码方式。常见转换流有两个 ——InputStreamReader和OutputStreamWriter。2.4.1 InputStreamReader :*InputStreamReader是Reader抽象类的一个子类因此它本身属于字符流范畴*。完成转换所调用的构造器如下需要传入一个InputStream类的子类对象以及一个编码类型。packagecsdn.knowledge.api_tools.iocurrent.transformation;importjava.io.*;importstaticjava.nio.charset.StandardCharsets.UTF_8;publicclassInputStreamReader_Demo{publicstaticvoidmain(String[]args)throwsIOException{InputStreamReaderinputStreamReadernewInputStreamReader(newFileInputStream(D:\\JAVA\\IDEA\\file\\3.txt),UTF_8);BufferedReaderbufferedReadernewBufferedReader(inputStreamReader);Stringdata;while((databufferedReader.readLine())!null){System.out.println(data);}bufferedReader.close();}}2.4.1 OutputStreamWriter*OutputStreamWriter类继承自Writer类转换方法与InputStreamWriter同理****。 以OutputStreamWriter_Demo类为演示类代码如下 :packagecsdn.knowledge.api_tools.iocurrent.transformation;importjava.io.FileNotFoundException;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.OutputStreamWriter;/** * author : Cyan_RA9 * version : 21.0 */publicclassOutputStreamWriter_Demo{publicstaticvoidmain(String[]args)throwsIOException{OutputStreamWriteroutputStreamWriternewOutputStreamWriter(newFileOutputStream(D:\\JAVA\\IDEA\\fileEX\\1.txt),UTF-16);outputStreamWriter.write(Space-X, 星舰发射);outputStreamWriter.close();}}以上便是Java IO流中的全部内容欢迎站中大佬指出不足笔者编写不宜恳求一枚点赞收藏评论
返回列表