IO流
啥是流
1 、IO :输入 \ 输出流:一种抽象概念,是对数据传输的总称,也就是说,数据在设备间的传输称为流,流的本质,是数据传输IO 流,就是用来,处理设备间的数据传输问题的。如:文件复制、文件上传、文件下载2 、按照,数据类型,分类1 、字节流:字节输入流:InputStream 作为基类字节输出流:OutputStream 作为基类2 、字符流:字符输入流:字符输入流 Reader 作为基类字符输出流:字符输出流 Writer 作为基类按照,流向,分类1 、输出流:OutputStream 、Writer 作为基类2 、输入流:InputStream 、Reader 作为基类一般来说,所说的"IO流的分类" 是按照"数据类型" 来分的。
字节流读数据
1 、"字节流" 抽象基类InputStream :这个抽象类,是,字节输入流的所有类的超类OutputStream :这个抽象类,是,字节输出流的所有类的超类子类名特点:子类名称,都是以其父类名作为子类名的后缀
常用方法
1 、InputStream 类的常用方法int read ( int b) 用于从输入流中读取下一个字节的数据,并返回这个字节的整数值(0 - 255 ),当调用 read ( int b) 方法时,它会从输入流中读取下一个字节的数据,并将这个字节的整数值返回,如果成功读取到数据,返回值是表示该字节的整数值(0 - 255 ),如果已经到达流的末尾,即没有更多可用的数据可读取,此时返回值是 - 1 ,这个方法的返回值是一个整数,范围在 0 到 255 之间,表示读取到的字节的值。如果返回 - 1 ,表示已经读取到流的末尾,没有更多数据可供读取。总之,int read ( int b) 方法用于逐个读取字节数据,并以整数形式返回每个字节的值,直到到达流的末尾为止。int read ( byte [ ] b) 从输入流中读取数据,并将数据存储在"缓冲区数组b" 中,它返回实际读取的字节数,如果,因为已经到达流的末尾,而没有更多的数据可读,则可能返回小于数组长度的值,如果,发生I / O 错误,将抛出IOException 。说白了就是:fis. read ( buffer) 方法,返回的是实际从输入流中读取的字节数,具体来说,这个方法的作用是,从"FileInputStream对象fis" 中读取数据,并将读取到的字节内容,存储到指定的"字节数组buffer" 中。当 fis. read ( buffer) 方法被调用时,它会尽可能地读取数据填充到"buffer数组" 中,返回实际读取的字节数,如果,成功读取了数据,则返回的是实际读取的字节数,如果,已经到达文件末尾,返回值将是"-1" 。再解释:fis. read ( buffer) 是一次性读取数据到指定的"字节数组buffer" 中,返回值bytesRead是"实际读取的字节数,而不是总的字节数" 。如果bytesRead的值,等于 buffer的长度,表示,整个 buffer 数组已经被填满,里面包含了读取的数据。如果bytesRead的值,小于 buffer的长度,表示,只有部分数据被读取到 buffer 中。int read ( byte [ ] b, int off, int len) 从输入流中读取最多len个字节的数据,并将这些数据存储到字节数组b中,从数组索引off开始的位置,它返回实际读取的字节数,如果,因为已经到达流的末尾,而没有更多的数据可读,则返回的字节数可能小于lenvoid close ( ) 关闭输入流,关闭一个已经关闭的流是合法的,调用多次close ( ) 方法不会有任何效果,一旦流被关闭,任何后续尝试从流中读取数据或写入数据都将抛出IOException 。2 、InputStream 类,常用的子类有FileInputStream ,用于从文件中读取数据FileInputStream :是Java 的一个类,它用于,从文件中读取原始的字节流,当你需要读取文件内容,并将其作为字节序列处理时,可以使用FileInputStream 类。这个类的构造函数:FileInputStream ( String name) 接受一个String 类型的参数,这个参数是文件在文件系统中的路径名,当调用这个构造函数时,Java 会在指定的路径下打开这个文件,并创建一个与这个文件相连接的FileInputStream 对象,一旦对象被创建,你就可以使用它的方法来读取文件内容了。
例子
需求:"读取文件中的内容,然后输出" import java. io. FileInputStream ;
import java. io. IOException ;
public class StudyIO { public static void main ( String [ ] args) { String filePath = "D:/io/hello.txt" ; FileInputStream fis = null ; try { fis = new FileInputStream ( filePath) ; byte [ ] buffer = new byte [ 1024 ] ; int bytesRead; while ( ( bytesRead = fis. read ( buffer) ) != - 1 ) { String data = new String ( buffer, 0 , bytesRead) ; System . out. print ( data) ; } } catch ( IOException e) { e. printStackTrace ( ) ; } finally { try { if ( fis != null ) { fis. close ( ) ; } } catch ( IOException e) { e. printStackTrace ( ) ; } } }
}
字节流写数据
"字节流" 抽象基类InputStream :这个抽象类,是,字节输入流的所有类的超类OutputStream :这个抽象类,是,字节输出流的所有类的超类子类名特点:子类名称,都是以其父类名作为子类名的后缀
常用方法
1 、OutputStream 类的常用方法void write ( int c) 将指定的字节( 通过其整数表示形式) 写入文件输出流,实际上,它会取int 参数的低8 位( 即一个字节) 并将其写入文件。FileOutputStream fos = new FileOutputStream ( "example.txt" ) ; fos. write ( 65 ) ; fos. close ( ) ; void write ( byte [ ] buf) 将整个字节数组写入文件输出流。它会写入数组中的每个字节,直到数组结束。byte [ ] data = { 'H' , 'e' , 'l' , 'l' , 'o' } ; FileOutputStream fos = new FileOutputStream ( "example.txt" ) ; fos. write ( data) ; fos. close ( ) void write ( byte [ ] b, int off, int len) 从字节数组的指定偏移量开始,写入指定长度的字节到文件输出流,off:开始写入的数组中的偏移量,len:要写入的字节数,byte [ ] data = { 'a' , 'b' , 'c' , 'd' , 'e' , 'f' } ; FileOutputStream fos = new FileOutputStream ( "example.txt" ) ; fos. write ( data, 2 , 3 ) ; fos. close ( ) ; void close ( ) 此方法关闭文件输出流,一旦流被关闭,任何进一步的写操作都会抛出IOException 2 、"OutputStream类" 常用的子类有"FileOutputStream" ,用于向文件中写入数据,a. FileOutputStream( String name) 创建一个文件输出流以指定的名称写入文件,如果文件不存在,则尝试创建它;如果文件已经存在,则其内容将被覆盖。b. FileOutputStream( File file) 使用"File对象" 创建一个文件输出流以写入文件。c. FileOutputStream( FileDescriptor fdObj) 使用"文件描述符" 创建一个文件输出流,文件描述符,通常与已经打开的文件相关联。使用"FileOutputStream" 时,通常会使用"try-with-resources" 语句,来确保流在不再需要时自动关闭,这样可以避免资源泄漏。
例子
import java. io. FileOutputStream ;
import java. io. IOException ; public class StudyIO_2 { public static void main ( String [ ] args) { String testWriteName = "D:/io/test.txt" ; byte [ ] data = "Hello-World!" . getBytes ( ) ; try ( FileOutputStream fos = new FileOutputStream ( testWriteName) ) { fos. write ( data) ; System . out. println ( "Data written to " + testWriteName) ; } catch ( IOException e) { e. printStackTrace ( ) ; System . out. println ( "Data written to " + testWriteName) ; } }
}
文件复制功能
import java. io. FileInputStream ;
import java. io. FileOutputStream ;
import java. io. IOException ;
public class FileCopy { public static void main ( String [ ] args) { FileOutputStream fos = null ; FileInputStream fis = null ; try { fis = new FileInputStream ( "D:/io/test.txt" ) ; fos = new FileOutputStream ( "D:/io/dnf-2.txt" ) ; byte [ ] buffer = new byte [ 1024 ] ; int bytesRead; while ( ( bytesRead = fis. read ( buffer) ) != - 1 ) { fos. write ( buffer, 0 , bytesRead) ; } } catch ( IOException e) { e. printStackTrace ( ) ; } finally { try { if ( fis != null ) fis. close ( ) ; if ( fos != null ) fos. close ( ) ; } catch ( IOException e) { e. printStackTrace ( ) ; } } }
}
字节缓冲流
1 、"BufferedOutputStream" :该类实现缓冲输出流,通过设置这样的输出流,应用程序,可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。构造方法:字节缓冲输出流 BufferedOutputStream ( OutputStream out) 2 、"BufferedInputStream" :创建BufferedInputStream ,将创建一个内部的缓冲数组,当从流中读取,或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节构造方法:字节缓冲输入流 BufferedInputStream ( InputStream in) "综合1、2" :为什么,构造方法需要的是字节流,而不是具体的文件或者路径呢?因为,字节缓冲流,仅仅提供缓冲区,而真正的读写数据,还得依靠"基本的字节流对象" 进行操作。"chatGPT的解释" :在Java 的I / O 流框架中,"BufferedOutputStream" 和 "BufferedInputStream" ,都是用于提高I / O 操作效率的缓冲流。a. 它们的工作原理是:在内存中创建一个缓冲区,这个缓冲区用于临时存储要写入或读取的数据。当向输出流写入数据时,数据首先被写入缓冲区,直到缓冲区满或者显式地调用flush ( ) 方法,才会将数据从缓冲区写入到底层的输出流。当从输入流读取数据时,会首先尝试从缓冲区中读取,如果缓冲区为空,则再从底层输入流中读取数据填充缓冲区。b. 构造方法,需要字节流( OutputStream 或 InputStream ) 作为参数,而不是具体的文件或路径,是因为,"BufferedOutputStream" 和 "BufferedInputStream" 被设计为通用的缓冲流,它们可以与任何实现了"OutputStream" 或 "InputStream" 接口的流对象一起使用,这意味着,它们不仅可以用于文件I / O ,还可以用于网络通信、内存流( 如ByteArrayOutputStream 和ByteArrayInputStream ) 等任何需要进行字节读写的地方。"总之" BufferedOutputStream ( OutputStream out) 这里的"out参数" ,是一个基本的"字节输出流对象" ,它可以是任何类型的输出流,比如:FileOutputStream 用于写入文件,SocketOutputStream 用于网络通信等,BufferedOutputStream 会将这个输出流包装起来,提供缓冲功能。BufferedInputStream ( InputStream in) 这里的"in参数" 是一个基本的"字节输入流对象" ,它也可以是任何类型的输入流,比如:FileInputStream 用于读取文件,SocketInputStream 用于从网络读取数据等,BufferedInputStream 会将这个输入流包装起来,提供缓冲功能。
例子
"需求" :有一个"source.txt" 的文件,我们想要将其内容复制到一个新的文件"target.txt" 中。"代码" :
import java. io. * ;
public class BufferedStreamsExample { public static void main ( String [ ] args) { File sourceFile = new File ( "D:/io/source.txt" ) ; File targetFile = new File ( "D:/io/target.txt" ) ; try ( BufferedInputStream bis = new BufferedInputStream ( new FileInputStream ( sourceFile) ) ; BufferedOutputStream bos = new BufferedOutputStream ( new FileOutputStream ( targetFile) ) ; ) { byte [ ] buffer = new byte [ 1024 ] ; int bytesRead; while ( ( bytesRead = bis. read ( buffer) ) != - 1 ) { bos. write ( buffer, 0 , bytesRead) ; } bos. flush ( ) ; System . out. println ( "文件复制完成" ) ; } catch ( IOException e) { e. printStackTrace ( ) ; System . out. println ( "文件复制过程中发生错误" ) ; } }
} "代码讲解" :
首先,创建一个BufferedInputStream 来读取source. txt文件的内容,创建一个BufferedOutputStream 来写入target. txt文件,其次,使用一个字节数组buffer作为中间缓冲区,在循环中不断地从源文件读取数据到缓冲区,然后,将缓冲区的数据写入目标文件,直到源文件的末尾,最后,调用bos. flush ( ) ,是为了确保所有缓冲的数据,都被写出到底层输出流中。