IO流
1.流的概念和作用
流是一组有序的,有起点和终点的字节的集合,是对数据传输的总称或者抽象说法。即数据在两个设备之间传输称为流,流的本质是数据传输;
按处理数据单元分类
字节流:以字节单位获取数据,命名上以stream结尾的流一般是字节流,eg:FileInputStream,FileOutputStream
字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,eg:FileReader,FileWriter
区别:
(1):读写单位不同,字节流以字节为单位(8bit),字符流以字符为单位,根据码表映射字符,一次可读多个字节。
(2):处理对象不同,字节流能处理所有类型的数据,图片,avi等;字符流只能处理字符类型的数据;
结论:只要是纯文本输出 使用字符流,除此之外都是用字节流;
按处理对象不同分类
节点流:可以直接从数据源或目的地读写数据
操作文件 | 操作数组 | 操作字符串 | 操作管道 |
---|---|---|---|
FileInputStream | ByteArrayInputStream | StringReader | PipedInputStream |
FileOutputStream | ByteArrayOutputStream | StringWriter | PipedOutputStream |
FileReader | CharArrayReader | / | PipedReader |
FileWriter | CharArrayWriter | / | PipedWriter |
处理流:也叫缓冲流,不直接链接到数据源或者目地,使用在节点流上的流称为处理流,通过对其他流的处理提升程序性能,处理流的构造方法总要带一个其他流的对象作为参数,一个流的对象经过其他流的包装称为流的链接。
(1):缓冲流:BufferedInputStream,BufferedOutputStream ,BufferReader,BufferWriter增加缓冲功能,避免频繁读写硬盘。
(2)转换流:InputStreamReader,OutputStreamReader 实现了字节流和字符流之间的转换。
(3):数据流:DataInputStream,DataOutputStream 等将其他基础数据类型写入到文件中,或者读取出来。
转换流:
InputStreamReader,OutputStreamWriter 需要InputStream或OutputStream作为参数,实现从字节流到到字符流的转换。
节点流处于IO操作的第一线,所有操作必须通过他们进行;处理流可以对节点流进行包装,提高性能或者提高程序的灵活性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N8x274UE-1620533981839)(C:\Users\Mr.zhang\Desktop\截图\stream.png)]
2.四大抽象类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uTj1jp47-1620533981842)(C:\Users\Mr.zhang\Desktop\截图\io1.png)]
3.总结
4.FileInputStream,FileOutputStream,读写取文件内容。
public static void main(String[] args) { String filePath = "C:\\Users\\Mr.zhang\\Desktop\\MarkDown\\ioTest\\iotest.txt"; //测试写入文件 writeFile(filePath,"今天也是做好人的一天,你很好"); //测试从文件中读取内容 System.out.println(readFile(filePath)); } /** * 将content写入指定文件 * @param filePath * @param content */ public static void writeFile(String filePath,String content){ FileOutputStream fileOutputStream = null; try { //1.根据文件路径创建输出流 fileOutputStream = new FileOutputStream(filePath); //2.把String转换成byte数组 byte[] bytes = content.getBytes(); //3.把bytes数组写入输出流中 fileOutputStream.write(bytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 读取文件内容 * @return */ public static String readFile(String filePath){ FileInputStream fileInputStream = null; String result = ""; try { //根据path路径实例化一个输入流的对象 fileInputStream = new FileInputStream(filePath); //返回这个输入流可以被都剩下的bytes字节的剩余量 int available = fileInputStream.available(); //创建一个接收数组 byte[] bytes = new byte[available]; fileInputStream.read(bytes); result = new String(bytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { fileInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return result; }
运行结果
今天也是做好人的一天,你很好 Process finished with exit code 0
5.File
文件和目录路径名的抽象表示,可以完成对所有文件的操作。
构造
public File(String pathname) //文件的绝对路径 public File(URI uri) //文件的URI地址 public File(String parent, String child) //指定父文件绝对路径、子文件绝对路径 public File(File parent, String child) //指定父文件、子文件相对路径 //下面这两个是File类中私有的构造函数,外面不能调用 private File(String child, File parent) private File(String pathname, int prefixLength)
感兴趣的方法 可以读取指定目录下的文件,可以通过FileFilter 过滤指定后缀的文件
static void flieListFilter(){ MyFileFlter myFileFlter =new MyFileFlter(".png"); File file = new File("C:\\Users\\Mr.zhang\\Desktop\\截图"); File[] files = file.listFiles(myFileFlter); for (File f : files) { System.out.println(f.getName()); } } static class MyFileFlter implements FileFilter{ String type; //文件类型 MyFileFlter(){ } MyFileFlter(String type){ this.type = type; } @Override public boolean accept(File pathname) { if(!pathname.isDirectory()){ pathname.getName().endsWith(type); return true; } return false; } }
6.缓冲流BufferedInputStream,BufferOutputStream
BufferedInputStream和BufferedOutputStream这两个类分别是FilterInputStream和FilterOutputStream的子类,作为装饰器子类,使用它们可以防止每次读取/发送数据时进行实际的写操作,代表着使用缓冲区。
我们有必要知道不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!
同时正因为它们实现了缓冲功能,所以要注意在使用BufferedOutputStream写完数据后,要调用flush()方法或close()方法,强行将缓冲区中的数据写出。否则可能无法写出数据。与之相似还BufferedReader和BufferedWriter两个类。
现在就可以回答在本文的开头提出的问题:
BufferedInputStream
和BufferedOutputStream
类就是实现了缓冲功能的输入流/输出流。使用带缓冲的输入输出流,效率更高,速度更快。
BufferedInputStream本质上是通过一个内部缓冲区数组实现的,BufferInputStream会将输入流的数据分批填入缓冲区中,每当缓冲区的数据被读取完之后,输入流会再次填入到缓冲区,如此反复;
那么什么时候flush()才有效呢?
答案是:当OutputStream是BufferedOutputStream时。
当写文件需要flush()的效果时,需要
FileOutputStream fos = new FileOutputStream(“c:\a.txt”);
BufferedOutputStream bos = new BufferedOutputStream(fos);
也就是说,需要将FileOutputStream作为BufferedOutputStream构造函数的参数传入,然后对BufferedOutputStream进行写入操作,才能利用缓冲及flush()。
查看BufferedOutputStream的源代码,发现所谓的buffer其实就是一个byte[]。
BufferedOutputStream的每一次write其实是将内容写入byte[],当buffer容量到达上限时,会触发真正的磁盘写入。
而另一种触发磁盘写入的办法就是调用flush()了。
BufferedOutputStream
在close()
时会自动flush
BufferedOutputStream
在不调用close()
的情况下,缓冲区不满,又需要把缓冲区的内容写入到文件或通过网络发送到别的机器时,才需要调用flush.
public static void main(String[] args) { //复制图片 copuFile("d:\\io2.png","C:\\Users\\Mr.zhang\\Desktop\\截图\\io1.png"); } /** * 复制图片 */ static void copuFile(String newFilePath,String oldFilePath){ InputStream inputStream = null; BufferedInputStream bis = null; OutputStream outputStream = null; BufferedOutputStream bos = null; File newFile = new File(newFilePath); File oldFile = new File(oldFilePath); try { inputStream = new FileInputStream(oldFile); //创建一个输入流 bis = new BufferedInputStream(inputStream); //对接缓冲流 outputStream = new FileOutputStream(newFile); //创建一个输出流 bos = new BufferedOutputStream(outputStream); //对接缓冲流 byte[] inputByte = new byte[1024]; //代表一次读取1kb 暂存从输入流读取的数据 int temp = 0; //代表实际读取的字节数 while ((temp=bis.read(inputByte))!=-1){ bos.write(inputByte,0,temp); } //主动刷新,将缓冲区的内容写入到文件 bos.flush(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(bos!=null){ try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } if(bis!=null){ try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } } }
close()方法的作用
关闭输入流,并且释放系统资源
BufferedInputStream装饰一个 InputStream 使之具有缓冲功能,is要关闭只需要调用最终被装饰出的对象的 close()方法即可,因为它最终会调用真正数据源对象的 close()方法。因此,可以只调用外层流的close方法关闭其装饰的内层流。
7.缓冲流BufferedReader,BufferWriter
方法
void close() // 关闭此流,但要先刷新它。 void flush() //刷新该流的缓冲。 void newLine() //写入一个行分隔符。 void write(char[] cbuf, int off, int len) //写入字符数组的某一部分。 void write(int c) //写入单个字符。 void write(String s, int off, int len) //写入字符串的某一部分。
Test
public static void main(String[] args) { copyFile("D:/newTest.txt","C:\\Users\\Mr.zhang\\Desktop\\MarkDown\\ioTest\\iotest.txt"); } /** * 复制txt文件 * @param newFileStr * @param oldFileStr */ static void copyFile(String newFileStr,String oldFileStr){ FileReader fileReader = null; BufferedReader bufferedReader = null; FileWriter fileWriter = null; BufferedWriter bufferedWriter = null; File newFile = new File(newFileStr); File oldFile = new File(oldFileStr); try { fileReader = new FileReader(oldFile); //创建FileReader读字符流 bufferedReader = new BufferedReader(fileReader); //接入缓冲流 fileWriter = new FileWriter(newFile); //创建FileWriter写字符流 bufferedWriter = new BufferedWriter(fileWriter); //接入缓冲流 String result = null; //每次读取内容 while (( result = bufferedReader.readLine() ) != null){ bufferedWriter.write(result); bufferedWriter.newLine(); //换行 } bufferedWriter.flush(); //强制把数组内容写入文件 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(bufferedWriter!=null){ try { bufferedWriter.close(); } catch (IOException e) { e.printStackTrace(); } } if(bufferedReader!=null){ try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
8.转换流 InputStreamReader,OutputStreamWriter
InputStreamReader简介 是字符流Reader的子类,是字节流通向字符流桥梁,你可以在构造器中指定编码的方式,如果不指定将采用底层操作系统的默认方式,要启用从字节到字符的转换,可以提前从底层读取更多的字节,使其超过满足当前读取操作所需的字节。
构造
InputStreamReader(Inputstream in) //创建一个使用默认字符集的 InputStreamReader。 InputStreamReader(Inputstream in,Charset cs) //创建使用给定字符集的 InputStreamReader。 InputStreamReader(InputStream in, CharsetDecoder dec) //创建使用给定字符集解码器的 InputStreamReader。 InputStreamReader(InputStream in, String charsetName) //创建使用指定字符集的 InputStreamReader。
方法
void close() // 关闭该流并释放与之关联的所有资源。 String getEncoding() //返回此流使用的字符编码的名称。 int read() //读取单个字符。 int read(char[] cbuf, int offset, int length) //将字符读入数组中的某一部分。 boolean ready() //判断此流是否已经准备好用于读取。
OutputStreamWriter简介 是字符流Writer的子类,是字符流通向字节流的桥梁,每次调用write()方法会导致在给定字符上调用编码转换器,再写入之前,得到的这些字节流将在缓冲区累计。
构造
OutputStreamWriter(OutputStream out) //创建使用默认字符编码的 OutputStreamWriter OutputStreamWriter(OutputStream out, String charsetName) //创建使用指定字符集的 OutputStreamWriter。 OutputStreamWriter(OutputStream out, Charset cs) //创建使用给定字符集的 OutputStreamWriter。 OutputStreamWriter(OutputStream out, CharsetEncoder enc) //创建使用给定字符集编码器的 OutputStreamWriter。
方法
void write(int c) //写入的字符长度 void write(char cbuf[]) //写入的字符数组 void write(String str) //写入的字符串 void write(String str, int off, int len) //应该写入的字符串,开始写入的索引位置,写入的长度 void close() //关闭该流并释放与之关联的所有资源。
public static void main(String[] args) { copyFile("D:/new2Test.txt","C:\\Users\\Mr.zhang\\Desktop\\MarkDown\\ioTest\\iotest.txt"); } /** * 复制txt文件 * @param newFileStr * @param oldFileStr */ static void copyFile(String newFileStr,String oldFileStr){ InputStream inputStream = null; InputStreamReader inputStreamReader = null; OutputStream outputStream = null; OutputStreamWriter outputStreamWriter = null; File newFile = new File(newFileStr); File oldFile = new File(oldFileStr); try { inputStream = new FileInputStream(oldFile); //创建输入流 inputStreamReader = new InputStreamReader(inputStream); //创建转换输入流 outputStream = new FileOutputStream(newFile); //创建输出流 outputStreamWriter = new OutputStreamWriter(outputStream); //创建转换输出流 int temp = 0; //每次读取内容 while (( temp = inputStreamReader.read() ) != -1){ System.out.println(temp); outputStreamWriter.write(temp); //读取二进制数据 } outputStreamWriter.flush(); //强制把数组内容写入文件 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { if(outputStreamWriter!=null){ try { outputStreamWriter.close(); } catch (IOException e) { e.printStackTrace(); } } if(inputStreamReader!=null){ try { inputStreamReader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
- 字节数组ByteArrayInputStream,ByteArrayOutputStream
ByteArrayInputStream 可以将字节数组转换为输入流;
ByteArrayOutputStream 可以捕获内存缓冲区中的数据,转换成字节数组;
ByteArrayInputStream
构造
public ByteArrayInputStream(byte buf[]) public ByteArrayInputStream(byte buf[], int offset, int length)
一般方法
void close() // 关闭该流并释放与之关联的所有资源。 String getEncoding() //返回此流使用的字符编码的名称。 int read() //读取单个字符。 int read(char[] cbuf, int offset, int length) //将字符读入数组中的某一部分。 boolean ready() //判断此流是否已经准备好用于读取。
String msg = "hello,world"; byte[] b = msg.getBytes(); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(b); int temp = -1; while ((temp=byteArrayInputStream.read())!=-1){ System.out.println((char)temp); } try { byteArrayInputStream.close(); } catch (IOException e) { e.printStackTrace(); } }
-构造
~~~java
public ByteArrayOutputStream()
public ByteArrayOutputStream(int size)
~~~
-一般方法
void write(int b) void write(byte b[], int off, int len) void writeTo(OutputStream out) byte toByteArray()[] void close()
public static void main(String[] args) throws IOException { String mes = "你好,world" ; byte[] b = mes.getBytes() ; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); FileOutputStream fileOutputStream = null; try { byteArrayOutputStream.write(b); fileOutputStream = new FileOutputStream("D:/byteArrayoutputstreamTest.txt"); byteArrayOutputStream.writeTo(fileOutputStream); fileOutputStream.flush(); } catch (IOException e) { e.printStackTrace(); }finally { if(fileOutputStream!=null){ fileOutputStream.close(); } if(byteArrayOutputStream!=null){ byteArrayOutputStream.close(); } } }
10.FileUtils 工具类
Commons io
Apache Commons IO是Apache基金会创建并维护的Java函数库。它提供了许多类使得开发者的常见任务变得简单,同时减少重复代码,这些代码可能遍布于每个独立的项目中,你却不得不重复的编写。
这里集成有很多对文件操作的方法,包括对集合的操作;
复制文件
复制文件夹
下载文件copyURLToFile(final URL source, final File destination)
字符串写入文件writeStringToFile(final File file, final String data, final String encoding) writeStringToFile(final File file, final String data, final Charset encoding, final boolean append)
把字节数组写入文件
void writeByteArrayToFile(final File file, final byte[] data) void writeByteArrayToFile(final File file, final byte[] data, final boolean append) void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append)
把集合里面的内容写入文件
void writeLines(final File file, final Collection<?> lines) void writeLines(final File file, final Collection<?> lines, final boolean append) void writeLines(final File file, final String encoding, final Collection<?> lines) void writeLines(final File file, final String encoding, final Collection<?> lines, final boolean append) void writeLines(final File file, final String encoding, final Collection<?> lines, final String lineEnding) void writeLines(final File file, final String encoding, final Collection<?> lines, final String lineEnding, final boolean append) void writeLines(final File file, final Collection<?> lines, final String lineEnding) void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append)