泰州做网站需要多少钱/seo搜索引擎推广什么意思
I/O流
一、IO产生的原因
- 在操作系统中,一切数据都以文件的形式存储。需要长久保存的文件数据,存储在外部设备。
- 程序运行时,所有的数据都需要在内存中,同时,内存的大小有限,因此常常需要在内存和外设之间交换数据,即I/O、
- 在Java语言中主要通过输入流和输出流,完成I/O的功能,从而实现和外设的数据交互
二、IO流
IO流用来处理JVM内存和外部设备之间的数据传输。在Java中,我们通过流(Stream)的方式完成对数据进行输入、输出的操作。
1. IO流的分类
根据数据的流动方向:
- 输入流(对数据的读入,将外部设备数据读入JVM内存)
- 输出流(对数据的写出,将数据从JVM内存写出到外部设备)
根据流中的内容:
- 字节流(流中的数据,是以字节为单位的二进制数据)
- 字符流(流中的数据是以字符为单位的字符数据)
字符流和字节流的使用场景:
字符流 ——> 文本编辑器可以打开,并且人可以看懂的数据
字节流 ——> 字节流可以操作一切类型的数据,只是有时操作字符数据不太方便,所以字符数据专门交给字符流处理
2. IO流的基类
字节流
- 输入流 ——> InputStream (抽象类)
- 输出流 ——> OutputStream (抽象类)
字符流
- 输入流 ——> Reader (抽象类)
- 输出流 ——> Writer (抽象类)
由这四个类派生出来的子类名称都是以期父类名作为子类名的后缀
如:InputStream的子类FileInputStream
如:Reader的子类FileReader
3. 字节流
3.1 输入流(InputStream)
实例化:InputStream是抽象类,无法直接实例化,只能间接实例化。因为通常操作的都是文件数据,所以使用其操作文件的具体子类FileInputStream实例化。
FileInputStream的构造方法:
- FileInputStream(File file)
- FileInputStream(String name)
注:目标文件必须存在,否则会报错(系统找不到指定的文件)
// 创建输入流对象,并将数据保存到流对象中public void constructor() throws FileNotFoundException {// 把外部数据读入到输入流中// FileInputStream(File file)File file = new File("a.txt");InputStream in1 = new FileInputStream(file);// FileInputStream(String name)InputStream in2 = new FileInputStream("b.txt");
}
从外设读取数据:
- public int read()
- public int read(byte[] b)
// 从输入流中读取数据的下一个字节// 一次读取一个字符 public int read()@Testpublic void readSingleByte() throws IOException {// 1、创建输入流对象InputStream ins = new FileInputStream("a.txt");// 2、从目标文件读取数据// int read(),有数据则返回字符的ASCII码,没有则返回-1int readByte;while ((readByte = ins.read()) != -1) {char c = (char) readByte;System.out.println(c);}// 3、关闭流对象ins.close();}// 从数据流中一次读取全部数据 public int read(byte[] b)@Testpublic void readAllBytes() throws IOException {// 1、创建输入流对象InputStream ins = new FileInputStream("a.txt");// 2、从目标文件中读取数据// int read(byte[] b)// 实际开发中,通常给1024的整数倍 2^10byte[] buffer = new byte[1024];//ins.read(buffer);//System.out.println(Arrays.toString(buffer));// len表示我们向字节数组中实际填充了多少字节int len = ins.read(buffer);String s = new String(buffer, 0, len);System.out.println(s);// 3、关闭流对象ins.close();}
一次读入或写出一个字节效率高,还是一次读入或写出一个字节数组效率高:
- 一个字节数组效率高
- 原因:
- 每次读入或写出(即每次和外设的数据交互),都需要依赖操作系统的内核实现,这意味着每次读入或写出,都需要付出额外的通信代价
- 一次读入或写出一个字节数组的数据,平均到每个字节,付出的额外代价要少很多
3.2 输出流(OutputStream)
实例化:OutputStream是抽象类,无法直接实例化,只能间接实例化。因为,通常操作的都是文件数据,所以使用期操作文件的具体子类FileOutputStream实例化。
FileOutputStream的构造方法:
- FileOutputStream(File file)
- FileOutputStream(String name)
// 若目标文件不存在,会自动创建@Testpublic void constructor() throws FileNotFoundException {// FileOutputStream(File file)File file = new File("c.txt");OutputStream os1 = new FileOutputStream(file);//FileOutputStream(String name)OutputStream os2 = new FileOutputStream("d.txt");}
向外设写出数据:
- public void write(int b)
- publci void write (byte[] b)
- public void write(byte[] b, int off, int len)
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;/***** OutputStream的write方法* void write(int b)将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。* void write(byte[] b)将 b.length 个字节从指定的 byte 数组写入此输出流。void write(byte[] b, int off, int len)将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。参数:b - 数据。off - 数据中的初始偏移量。len - 要写入的字节数。*/
public class Demo2 {public static void main(String[] args) throws IOException {//void write(int b)//writeSingleByte();//void write(byte[] b)//writeAllBytes();//void write(byte[] b, int off, int len)writePartialBytes();}private static void writePartialBytes() throws IOException {// 1. 创建流对象OutputStream out = new FileOutputStream("a.txt");// 2. 通过写方法向输出流写入数据byte[] bytes = "hello world".getBytes();// void write(byte[] b, int off, int len)//out.write(bytes, 0, bytes.length);// 再比如,写入world这个字符串,到目标文件out.write(bytes, 6, 5);//3. 关闭流,并释放系统资源out.close();}private static void writeAllBytes() throws IOException {// 1. 创建流对象OutputStream out = new FileOutputStream("a.txt");// 2. 通过写方法向输出流写入数据byte[] bytes = "hello world".getBytes();// void write(byte[] b)out.write(bytes);//3. 关闭流,并释放系统资源out.close();}private static void writeSingleByte() throws IOException {// 1. 创建流对象OutputStream out = new FileOutputStream("a.txt");// 2. 通过写方法向输出流写入数据//int a = 97; // 'a'char c = 'a';out.write(c);// 向 文本文件中写入 "hello world"//byte[] bytes = "hello world".getBytes();//for (int i = 0; i < bytes.length; i++) {// out.write(bytes[i]);//}//3. 关闭流,并释放系统资源out.close();}}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;/**** 字节流写数据常见问题:1.创建文件字节输出流到底做了哪些事情?1). 创建FileOutputStream对象的时候,jvm首先到操作系统,查找目标文件a. 当发现目标文件 不存在的时候, jvm会首先创建该目标文件(内容为空, 前提是该目标文件的父目录存在)b. 当发现目标文件存在的时候, jvm默认会首先清空目标文件内容,最好准备让,FileOutputStream, 从文件头,开始写入数据2). 在内存中,创建FileOutputStream对象3). 在FileOutputStream对象和目标文件之间建立数据传输通道2.数据写成功后,为什么要close()?通过流的close方法:a. 关闭流b. 释放系统资源、3.如何实现数据的换行? 在要换行的地方,向文件中写入换行符即可 '\n'换行符,在不同的操作系统中,表示方式是不一样的:a. 类unix操作系统中:'\n'b. windows默认的换行表示: '\r'+'\n' 用windows自带的文本编辑器对于\n是否有换行效果,还和操作系统版本有关4.如何实现数据的追加写入?a. 对于同一输出流对象,多次写入的数据,会依次写入目标文件,先写入的数据在前,后写入的数据在后(非追加写入)b. 所谓追加写入,针对的是不同的输出流对象,向文件写入数据的情况,所谓追加写入,是指当使用不同的输出流对象向文件中写入数据的时候,从文件已有内容之后开始写入FileOutputStream(String name, boolean append)创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处FileOutputStream(File file, boolean append)创建一个向指定 File 对象表示的文件中写入数据的文件输出流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处5.给I/0流操作加上异常处理*/
public class Demo3 {public static void main(String[] args) {// 问题 1-4//question1To4();//加上异常处理的输出流代码// 1.创建文件字节输出流对象OutputStream out = null;try {out = new FileOutputStream("a.txt", true);// 2. 向目标文件写入数据byte[] bytes = "lee million".getBytes();out.write(bytes, 0, bytes.length);// 向文件中写入换行符String lineSeparator = System.lineSeparator();out.write(lineSeparator.getBytes());bytes = "zhangsan".getBytes();out.write(bytes, 0, bytes.length);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 3. 关闭流并释放资源try {if (out != null) {out.close();}} catch (IOException e) {e.printStackTrace();}}}private static void question1To4() throws IOException {// 1.创建文件字节输出流对象OutputStream out = new FileOutputStream("a.txt", true);// 2. 向目标文件写入数据byte[] bytes = "lee million".getBytes();out.write(bytes, 0, bytes.length);// 向文件中写入换行符String lineSeparator = System.lineSeparator();out.write(lineSeparator.getBytes());bytes = "zhangsan".getBytes();out.write(bytes, 0, bytes.length);// 3. 关闭流并释放资源out.close();// 返回和操作系统相关的换行符字符串//String s = System.lineSeparator();//System.out.println("\r\n".equals(s));}}
字节流写出数据的常见问题:
- 创建字节输出流做了哪些事情?
- FileOutputStream会先在操作系统中找到目标文件
- 如果目标文件不存在,FileOutputStream会创建该文件
- 如果目标文件存在,则不再重新创建,清空文件内容,从文件最开始的地方写入
- 在内存中,创建FileOutputStream对象
- 在FileOutputStream和目标文件之间建立数据传输通道
- 数据写出成功后,为什么要close()?
- 关闭此输出流并释放与此流相关的所有系统资源
- 如何实现数据的换行?利用换行符
- 如何实现数据的追加写入?
- FileOutputStream(File file,boolean append)
- 创建一个向指定File对象表示的文件中写出数据的文件输出流。如果第二和参数为true,则将字节写入文件末尾处,而不是写入文件开始处
- 给I/O流操作加上异常处理
3.3 字节缓冲流
产生原因:
- 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多
- 这是加入了数组这样的缓冲效果
- Java本身在设计的时候,也考虑到了这样的情况,所以提供了字节缓冲流
字节缓冲流:
- 字节缓冲输入流 ——> BufferedInputStream
- 字节缓冲输出流 ——> BufferedOutputStream
具体使用方法可以参考以下两个demo
package com.bytestream.bufferstream;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;/**** 字节缓冲流字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的情况,所以提供了字节缓冲区流字节缓冲输出流BufferedOutputStreamBufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。字节缓冲输入流BufferedInputStreamBufferedInputStream(InputStream in)创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。需要以其他流,作为初始化参数,从而创建出的流对象,这种流我们称为包装流对象,其类我们称为包装流如果过要关闭包装流对象,只需要关闭,包装流对象即可(不需要关心包装流所包装的底层流)。因为包装流会自己负责关闭,它所包装的底层流利用缓冲流复制文件*/
public class Demo1 {public static void main(String[] args) throws IOException {//basicUse();// 利用缓冲流复制文件InputStream in = new BufferedInputStream(new FileInputStream("d:\\a.txt"));OutputStream out = new BufferedOutputStream(new FileOutputStream("e:\\b.txt"));byte[] buf = new byte[4096];int len;while ((len = in.read(buf)) != -1) {// 将读取到的多个字节数据,写入输出流out.write(buf, 0, len);}//关闭流并释放资源in.close();out.close();}private static void basicUse() throws IOException {// 创建缓冲输出流对象FileOutputStream fos = new FileOutputStream("d.txt");OutputStream out = new BufferedOutputStream(fos);byte[] bytes = "hello buffer".getBytes();out.write(bytes); close包装流即可//关闭流释放资源out.close();//创建缓冲输入流对象FileInputStream fis = new FileInputStream("d.txt");InputStream in = new BufferedInputStream(fis);byte[] buffer = new byte[1024];int len = in.read(buffer);// close包装流即可in.close();System.out.println(new String(buffer, 0, len));}
}
package com.bytestream.bufferstream;import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;/**** public void flush() 刷新此缓冲的输出流。这迫使所有缓冲的输出字节被写出到底层输出流中。** public void close()关闭此输出流并释放与此流有关的所有系统资源。close 方法先调用其 flush 方法,然后调用其基础输出流的 close 方法**/
public class Demo2 {public static void main(String[] args) throws IOException {// 缓冲输出流BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("f.txt"));byte[] bytes = "hello zs".getBytes();bos.write(bytes);//bos.flush();bos.close();}}
四种复制方式的比较
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;/**** 比较四种复制方式的效率** 1. 不使用缓冲流* a. 一次复制一个字节数据* b. 一次复制一个字节数组的数据** 2. 使用缓冲流* a. 一次复制一个字节数据* b. 一次复制一个字节数组的数据*** 不使用缓冲流,一次复制一个字节* copyByte: 40275ms* 使用缓冲流一次复制一个字节copyByteInBuf: 380ms不使用缓冲流,一次复制一个字节数组copyBytes: 45ms使用缓冲流,一次复制一个字节数组copyBytesInBuf: 19ms**/
public class Comparison {public static void main(String[] args) throws IOException {File src = new File("e:\\copy\\vedio.mp4");File dest1 = new File("e:\\copy-vedio1.mp4");File dest2 = new File("e:\\copy-vedio2.mp4");File dest3 = new File("e:\\copy-vedio3.mp4");File dest4 = new File("e:\\copy-vedio4.mp4");//不用缓冲流,一次复制一个字节copyByte(src, dest1);//使用缓冲流,一次复制一个字节//copyByteInBuf(src, dest2);//不使用缓冲流,一次复制一个字节数组数据//copyBytes(src, dest3);//使用缓冲流,一次复制一个字节数组数据//copyBytesInBuf(src, dest4);}/*** 一次读写一个字节*/public static void copyByte(File srcFile, File destFile) throws IOException {//创建输入流对象FileInputStream fis = new FileInputStream(srcFile);//创建输出流对象FileOutputStream fos = new FileOutputStream(destFile);int readByte;//记录当前时间的毫秒值long start = System.currentTimeMillis();//开始一个字节一个字节的复制while ((readByte = fis.read()) != -1) {fos.write(readByte);}//记录复制完成之后的一个时间的毫秒值long end = System.currentTimeMillis();System.out.println("copyByte: " + (end - start));fis.close();fos.close();}/*** 一次读写一个字节 但是用的是缓冲流*/public static void copyByteInBuf(File srcFile, File destFile) throws IOException {//创建输入流对象FileInputStream fis = new FileInputStream(srcFile);BufferedInputStream bis = new BufferedInputStream(fis);//创建输出流对象FileOutputStream fos = new FileOutputStream(destFile);BufferedOutputStream bos = new BufferedOutputStream(fos);int readByte;//开始一个字节一个字节的复制long start = System.currentTimeMillis();while ((readByte = bis.read()) != -1) {bos.write(readByte);}long end = System.currentTimeMillis();System.out.println("copyByteInBuf: " + (end - start));bis.close();bos.close();}/*** 一次读写一个字节数组*/public static void copyBytes(File srcFile, File destFile) throws IOException {//创建输入流对象FileInputStream fis = new FileInputStream(srcFile);//创建输出流对象FileOutputStream fos = new FileOutputStream(destFile);int len;byte[] buffer = new byte[2048];long start = System.currentTimeMillis();//开始一个字节一个字节的复制while ((len = fis.read(buffer)) != -1) {fos.write(buffer, 0, len);}long end = System.currentTimeMillis();System.out.println("copyBytes: " + (end - start));fis.close();fos.close();}/*** 一次读写一个字节数组,用缓冲流*/public static void copyBytesInBuf(File srcFile, File destFile) throws IOException {//创建输入流对象FileInputStream fis = new FileInputStream(srcFile);BufferedInputStream bis = new BufferedInputStream(fis);//创建输出流对象FileOutputStream fos = new FileOutputStream(destFile);BufferedOutputStream bos = new BufferedOutputStream(fos);int len;byte[] buffer = new byte[2048];long start = System.currentTimeMillis();//开始一个字节一个字节的复制while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);}long end = System.currentTimeMillis();System.out.println("copyBytesInBuf: " + (end - start));bis.close();bos.close();}}