IO概念
什么是IO
Java中IO操作主要是指使用java.io包下的内容,进行输入、输出操作。输入也叫做读取数据,输岀也叫做作写出数据。
IO的分类
根据数据的流向分为:输入流和输出流。
输入流:把数据从其他设备上读取到内存中的流。
输出流:把数据从内存中写出到其他设备上的流。
格局数据的类型分为:字节流和字符流。
顶级父类们
字节流
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都是一个ー个的字节,在传输时也是一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
字节输出流——OutputStream
java.io.OutputStream抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
java.io.OutputStream 1、public abstract void write(int b) throws IOException; // 将指定的字节输出流。 2、public void write(byte b[]) throws IOException{...}; // 将b.length字节从指定的字节数组写入此输出流。 3、public void write(byte b[], int off, int len) throws IOException{...}; // 从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。 4、public void flush() throws IOException{}; // 刷新此输出流并强制任何缓冲的输出字节被写出。 5、public void close() throws IOException {}; // 关闭此输出流并释放与此流相关联的任何系统资源。
FileOutputStream类
OutputStream抽象类,有很多的子类,其中FileOutputStream类是它其中一个简单的子类。
java.io.FileOutputStream是文件输出流,用于将数据写出到文件。
写出字节数据
写出字节:write(int b)方法,每次可以写出一个字节数据
字节输出流的使用步骤:
- 创建一个 FileOutputStream对象,构造方法中传递写入数据的目的地。
- 调用FileOutputStream对象中的方法write,把数据写入到文件中。
- 释放资源(流使用会占用一定的内存,使用完毕要把内存清空提供程序的效率)。
import java.io.FileOutputStream; import java.io.IOException; public class DemoFosWrite { public static void main(String[] args) throws IOException { // 使用文件名创建字节流对象 FileOutputStream fos = new FileOutputStream("FOS.txt"); // 写出数据 // 写出第一个字节 fos.write(97); // 写出第二个字节 fos.write(98); // 写出第三个字节 fos.write(99); // 关闭资源 fos.close(); } }
运行结果:生成了一个"FOS.txt"文件
FOS.txt文件大小是3个字节,内容是abc
写入数据的原理(内存-->硬盘):
Java程序 --> Java虚拟机 --> 操作系统 --> 操作系统调用写数据的方法 --> 把数据写到文件中
写数据的时候,会把要写入的数据转换为二进制数。在打开文件的时候,都会查询编码表(例如:ASCII表),把字节转换为字符表示。
write(byte b[])方法
作用:将b.length字节从指定的字节数组写入此输出流。
import java.io.FileOutputStream; import java.io.IOException; public class Demo01Write { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("FOS1.txt"); byte[] bytes = {97, 98, 99}; // 将3个字节从bytes字节数组写入fos输出流。 fos.write(bytes); fos.close(); } }
运行结果:生成了一个"FOS1.txt"文件
write(byte b[], int off, int len)方法
作用:从指定的字节数组写入len字节,从偏移量off开始输出到此输出流。
import java.io.FileOutputStream; import java.io.IOException; public class Demo02Write { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("FOS2.txt"); byte[] bytes = {97, 98, 99, 100, 101, 102}; // 将3个字节从bytes字节数组写入fos输出流。 fos.write(bytes, 1, 4); fos.close(); } }
运行结果:生成了一个"FOS2.txt"文件
write方法简单练习
import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; public class Demo03Write { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("FOS3.txt"); // 调用String类中的getBytes()方法,把一串字符转换为byte数组 byte[] bytes = "大佬,你好!".getBytes(); // 将该数组转换为集合输出 System.out.println(Arrays.toString(bytes)); // 将多个字节从bytes字节数组写入fos输出流。 fos.write(bytes); fos.close(); } }
控制台输出
[-27, -92, -89, -28, -67, -84, -17, -68, -116, -28, -67, -96, -27, -91, -67, -17, -68, -127]
运行结果:还生成了一个"FOS3.txt"文件
字节输出流的续写和换行
public FileOutputStream(File file, boolean append) // 创建文件输出流以写入由指定的File对象表示的文件。 public FileOutputStream(String name, boolean append) // 创建文件输出流以指定的名称写入文件。
这两个构造方法,参数中都需要传入一个 boolean类型的值,true表示追加数据,false表示清空原有数据这样创建的输出流对象,就可以指定是否追加续写了,代码使用演示:
import java.io.FileOutputStream; import java.io.IOException; public class Demo01OutputAppend { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("a.txt", true); // 往"a.txt"文件中写入"大佬,"内容 byte[] bytes1 = "大佬,".getBytes(); fos.write(bytes1); // 往"a.txt"文件中追加写入"你好!"内容 byte[] bytes2 = "你好!".getBytes(); fos.write(bytes2); fos.close(); } }
运行结果:生成了一个"a.txt"文件
如果需要换行:
import java.io.FileOutputStream; import java.io.IOException; public class Demo02OutputAppend { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("b.txt", true); // 往"a.txt"文件中写入"大佬,"内容 byte[] bytes1 = "大佬,".getBytes(); fos.write(bytes1); // 换行 "\n" 或者 "\r" byte[] bytes = "\n".getBytes(); fos.write(bytes); // 往"a.txt"文件中追加写入"你好!"内容 byte[] bytes2 = "你好!".getBytes(); fos.write(bytes2); fos.close(); } }
运行结果:生成了一个"b.txt"文件
字节输入流 —— InputStream
java.io.InputStream抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close() // 关闭此输入流并释放与此流相关联的任何系统资源。 public abstract int read() // 从输入流读取数据的下一个字节。 public int read(byte[] b) // 从输入流中读取一些字节数,并将它们存储到字节数组b中。
FileInputStream类
java.io.FileInputStream类是文件输入流,从文件中读取字节。
构造方法
public FileInputStream(String name) throws FileNotFoundException // 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名name命名。 public FileInputStream(File file) throws FileNotFoundException // 通过打开与实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的File对象file命名。
当我们创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException异常。
读取数据的原理(硬盘-->内存):
Java程序 --> Java虚拟机 --> 操作系统 --> 操作系统调用读取数据的方法 --> 读取文件
字节输入流的使用步骤:
1.创建FileInputStream对象,构造方法中绑定要读取的数据源。
2.使用FileInputStream对象中的方法read,读取文件。
3.释放资源。
下面这个例子中使用的read()方法是一个字节一个字节的读取的。
import java.io.FileInputStream; import java.io.IOException; public class DemoInputRead { public static void main(String[] args) throws IOException { // 创建FileInputStream对象,构造方法中绑定要读取的数据源 FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/A"); // 使用FileInputStream对象中的方法read,读取文件 // char=65 对应 A int lien0 = fis.read(); char c0 = (char) lien0; System.out.println(lien0 + "对应" + c0); // char=10 对应 /n int lien1 = fis.read(); char c1 = (char) lien1; System.out.println(lien1 + "对应" + c1); // char=66 对应 B int lien2 = fis.read(); char c2 = (char) lien2; System.out.println(lien2 + "对应" + c2); // char=10 对应 /n int lien3 = fis.read(); char c3 = (char) lien3; System.out.println(lien3 + "对应" + c3); // 释放资源 fis.close(); } }
文件A的内容:
如果已经将文件A的内容读取完了,那么再读取的话,会返回-1。
FileInputStream类中的部分方法
int available() // 返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。 void close() // 关闭此输入流并释放与该流关联的所有系统资源。 int read() // 从输入流中读取数据的下一个字节。 int read(byte b[]) // 从输入流中读取一定数量的字节,并将其存储在緩神区数组b中。 int read(byte b[], int off, int len) // 将输入流中最多len个数据字节读入byte数组。 long skip(long n) // 跳过和丢弃此输入流中数据的n个字节。
read(byte b[])方法
import java.io.FileInputStream; import java.io.IOException; public class Demo02InputRead { public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/B"); // 创建一个byte数组,存储读取的字节 byte[] bytes = new byte[2]; // 开始读取,每次读取两个 // 第一次读取: bytes = {97, 98},len1 = 2 int len1 = fis.read(bytes); System.out.println( "bytes = " + new String(bytes) + "\t\t" + "len = " + len1 ); // 开始读取,每次读取两个 // 第二次读取: bytes = {99, 100},len2 = 2 int len2 = fis.read(bytes); System.out.println( "bytes = " + new String(bytes) + "\t\t" + "len = " + len2 ); // 开始读取,每次读取两个 // 第三次读取: bytes = {101, 100},len3 = 2 int len3 = fis.read(bytes); System.out.println( "bytes = " + new String(bytes) + "\t\t" + "len = " + len3 ); // 开始读取,每次读取两个 // 第四次读取: bytes = {101, 100},len4 = 2 int len4 = fis.read(bytes); System.out.println( "bytes = " + new String(bytes) + "\t\t" + "len = " + len4 ); } }
文件B内容:
控制台输出
bytes = ab len = 2 bytes = cd len = 2 bytes = ed len = 1 bytes = ed len = -1
解析:
第一次读取:读取第1个字节和第2个字节,将初始数组的{0, 0} 替换为 {a, b}
第二次读取:读取第3个字节和第4个字节,将第一次读取后的数组的{a, b} 替换为 {c, d}
第三次读取:读取第5个字节,发现没有可以读取的了,于是将第二次读取的数组的 {c, d}里面的c替换为e,而d没得替换,即{e, d}
第四次读取:因为第三次读取的时候,已经读取完了,没有可以读取的了,依旧还是原来的数组{e, d}
第一次读取两个字节(len1=2),第二次读取两个字节(len2=2),第三次读取1个字节(len3=2),第四次没得读取(len4=-1)。
读取完后,再读取,返回值是-1。
字节流练习:图片复制
文件复制的步骤:
- 创建一个字节输入流对象,构造方法中绑定要读取的数据源。
- 创建一个字节输出流对象,构造方法中绑定要写入的目的地。
- 使用字节输入流对象中的方法read读取文件。
- 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。
- 释放资源。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class DemoCopyFile { public static void main(String[] args) throws IOException { // 创建一个字节输入流对象,构造方法中绑定要读取的数据源。 FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg"); // 创建一个字节输出流对象,构造方法中绑定要写入的目的地。 FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg"); // 使用字节输入流对象中的方法read读取文件。 int len = 0; while ((len = fis.read()) != -1) { // 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。 fos.write(len); } // 释放资源。先关闭写的,再关闭读的。 fis.close(); fos.close(); } }
运行结果:
程序优化:
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class Demo02CopyFile { public static void main(String[] args) throws IOException { // 创建一个字节输入流对象,构造方法中绑定要读取的数据源。 FileInputStream fis = new FileInputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/666.jpg"); // 创建一个字节输出流对象,构造方法中绑定要写入的目的地。 FileOutputStream fos = new FileOutputStream("/Users/liyihua/IdeaProjects/Study/src/view/study/demo30/999.jpg"); // 使用字节输入流对象中的方法read读取文件。 int len = 0; byte[] bytes = new byte[1024]; while ((len = fis.read(bytes)) != -1) { // 使用字节输出流中的方法write,把读取到的字节写入到目的地的文件中。 fos.write(bytes, 0, len); } // 释放资源。 fis.close(); fos.close(); } }
字符流
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储(如:"学生"两个字占用了四个字节)。所以Java提供一些字符流类,以字符为单位读写数据专门用于处理文本文件。
字符输入流 —— Reader
java.io.Reader抽象类是表示用于读取字符流的所有类的超类,可以读取字符信到内存中。它定义了字符输入流的基本共性功能方法。
public void close() // 关闭此流并释放与此流相关联的任何系统资源。 public int read() // 从输入流读取一个字符。 public int read(char[] chars) // 从输入流中读取一些字符,并将它们存储到字符数组chars中。
FileReader类
java.io.FileReader类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
原文地址:https://www.cnblogs.com/liyihua/p/12262136.html