IO流
IO流
I:input O:output
通过IO可以完成硬盘文件的读和写。
分类
- 按流的方向分类
输入流:侧重于读,数据从数据源读入程序。(从磁盘中的文件读到程序里)
输出流:侧重于写,数据从程序写出到目的地。(从程序写到磁盘中的文件里)
- 按处理的数据单元分类
字节流:以 字节(1Byte=8bit) 为单位进行读取或者写出数据。
字符流:以 字符为单位进行读取或者写出数据。
这种流是万能的,什么类型的文件都可以读取。包括:
文本文件,图片,声音文件,视频文件
等…
字节流:
InputStream:用于从输入源读取字节数据的抽象类。
FileInputStream:从文件中读取字节数据的类。
ByteArrayInputStream:从字节数组中读取字节数据的类。
BufferedInputStream:提供缓冲功能的字节输入流类。
DataInputStream:读取基本数据类型的字节输入流类。
字节流
FileInputStream(从磁盘中的文件写入程序里)
以字节流进行读取文件的类是FileInputStream,它是InputStream(字节输入流)抽象类的子类。
public static void main(String[] args) throws IOException {
//1. 连接数据:FileInputStream 直接与数据源连接,因此属于节点流
FileInputStream fis = new FileInputStream("D:\\1.txt");
//2. 循环逐个读取字节
int temp=0;
StringBuilder sb = new StringBuilder();
while ((temp=fis.read())!=-1)//如果文件中的字节读取完毕,则返回-1,否则返回该字节数值(0-255)
sb.append((char)temp);
System.out.println(sb.toString());
//3. 关闭流
fis.close();
}
(一个字节一个字节进行读取)
FileOutputStream(从程序写入磁盘中的文件里)
以字节流进行写出数据的类是FileOutputStream,它是OutputStream(字节输出流)抽象类的子类。
//代码2
public static void main(String[] args) throws IOException {
//1. 连接数据源:直接与数据源连接,因此属于节点流
FileInputStream fis_img = new FileInputStream("D:/1.jpg");
//2. 连接目的地:直接与目的地连接,因此属于节点流
FileOutputStream fos_img = new FileOutputStream("D:/2.jpg");
//3. 逐个读取字节,并将字节逐个写出
int temp=0;
while ((temp=fis_img.read())!=-1)
{
fos_img.write(temp);
}
//4. 关闭流
fos_img.flush();
fis_img.close();
fos_img.close();
}
设置缓冲区 byte[] buffer = new byte[1024];
上面这俩都是一个字节一个字节 读取或者写出数据的,如果一次读取多个字节,或者将多个字节写出,那肯定比上面这个效率高。
所以要有一个缓冲区,这个缓冲区就是每次将多个字节装进缓冲区,然后一次性从缓冲区里写出多个字节。
//代码3
public static void main(String[] args) throws IOException {
FileInputStream fis_img = new FileInputStream("D:/1.jpg");
FileOutputStream fos_img = new FileOutputStream("D:/2.jpg");
int temp=0;
byte[] buffer = new byte[1024];//设置缓冲区,缓冲区大小去2^n合适
while ((temp=fis_img.read(buffer))!=-1)//每次读取多个字节存入缓冲区
{
fos_img.write(buffer,0,temp);//每次将缓冲区中的多个字节写出
}
fos_img.flush();
fis_img.close();
fos_img.close();
}
自适应缓冲区大小available
上面这个是手动设置缓冲区大小,对于较小的文件来说,可以一次性搞定,就没必要分多次,因此将缓冲区的大小设置为文件内容的实际大小即可。
FileInputStream对象提供了一个估算文件字节个数的方法available,通过该方法获取文件字节个数。
缓冲区的空间来自内存,缓冲区越大,那么占用的空间越大,因此,一次性读写数据只适用于较小的数据。
//代码4
public static void main(String[] args) throws IOException {
FileInputStream fis_img = new FileInputStream("D:/1.jpg");
FileOutputStream fos_img = new FileOutputStream("D:/2.jpg");
int temp=0;
//fis_img.available()直接获取数据的长度,类似一次搬完,不用分批,
//但这比较占内存,因此适用于小文件,比如一个人只能扛100斤苹果,你让他一次扛200斤,那就累趴了。
byte[] buffer = new byte[fis_img.available()];
fis_img.read(buffer);
fos_img.write(buffer);
fos_img.flush();
fis_img.close();
fos_img.close();
}
BufferedInputStream和BufferedOutputStream
根据通过缓冲区提高IO效率的思想,Java提供了BufferedInputStream和BufferedOutputStream两个处理流,来实现通过缓冲区读写文件。
//代码5
public static void main(String[] args) {
FileInputStream fis=null;//节点流
FileOutputStream fos=null;//节点流
BufferedInputStream bis=null;//处理流:缓冲流,实现原理就是通过缓冲区提高读效率
BufferedOutputStream bos=null;//处理流:缓冲流,实现原理就是通过缓冲区提高写效率
try {
fis = new FileInputStream("D:/1.jpg");
bis=new BufferedInputStream(fis);
fos=new FileOutputStream("D:/2.jpg");
bos=new BufferedOutputStream(fos);
//默认缓冲区大小:DEFAULT_BUFFER_SIZE = 8192;
int temp=0;
while ((temp=bis.read())!=-1)
{
bos.write(temp);
}
bos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
//流的关闭顺序:后开的先关
try {
if (bis!=null)
bis.close();
if (fis!=null)
fis.close();
if (bos!=null)
bos.close();
if (fos!=null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节数组流
ByteArrayInputStream(从磁盘中的文件写入程序里)
将内存中的字节数组对象作为数据源
//代码6
public static void main(String[] args) throws IOException {
byte[] source="mekeater".getBytes();
//内存中的字节数组对象作为数据源
ByteArrayInputStream bis = new ByteArrayInputStream(source);
int temp=0;
StringBuilder sb = new StringBuilder();
while ((temp=bis.read())!=-1)
{
sb.append((char) temp);
}
System.out.println(sb.toString());
bis.close();
}
ByteArrayOutputStream(从程序写入磁盘中的文件里)
将读取的数据写入到字节数组输出流中
//代码7
public static void main(String[] args) throws IOException {
//将流中的数据写入到字节数组中
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write('m');
bos.write('e');
bos.write('k');
bos.write('e');
bos.write('a');
bos.write('t');
bos.write('e');
bos.write('r');
byte[] bytes = bos.toByteArray();
for (byte b : bytes) {
System.out.print((char) b);
}
bos.close();
}
随机访问流(可以根据指定位置,开始查找字节位置)
RandomAccessFile可以指定开始查找的字节位置
//代码8
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("D:/2.txt", "rw");
for (int i = 0; i < 10; i++) {
raf.writeInt(i);
}
raf.seek(4);//seek指定开始查找的位置从第4个字节开始,一个int整数占4个字节,因此从第二个位置查找
System.out.println(raf.readInt());
//隔一个位置查找一个
for (int i = 0; i < 10; i+=2) {
raf.seek(i*4);
System.out.printf(raf.readInt()+"\t");
}
System.out.println();
//seek指定位置,重新写入该位置的数据,替换原有数据
raf.seek(4);//指定第4个字节位置,即第二个整数
raf.writeInt(66);
raf.seek(0);//重新定位查找的起始位置
for (int i = 0; i < 10; i++) {
System.out.print(raf.readInt()+"\t");
}
}
数据流(实现基本类型数据序列化到文件)
DataOutputStream将基本数据类型的数据以字节流形式输出到本地文件(类似序列化,但是它只能对基本数据类型进行操作,不能对java自定义对象进行操作)
//代码9
public static void main(String[] args) throws IOException {
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("D:/data")));
//写出基本数据类型数据文件中
dos.writeChar('m');
dos.writeBoolean(false);
dos.writeDouble(Math.random());
dos.writeInt(66);
dos.writeUTF("Mekeater");
dos.flush();
dos.close();
}
DataInputStream从文件中读取存储的基本数据类型的数据
//代码10
public static void main(String[] args) throws IOException {
DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("D:/data")));
//注意读取数据顺序要去写入数据一致
System.out.println(dis.readChar());
System.out.println(dis.readBoolean());
System.out.println(dis.readDouble());
System.out.println(dis.readInt());
System.out.println(dis.readUTF());
dis.close();
}
对象流(实现基本类型数据及自定义对象数据序列化到文件)
Java IO中提供了ObjectOutputStream类实现对象的序列化。
反序列化:将二进制文件恢复为对象数据的过程。Java IO中提供了ObjecInputStream类实现对象的序列化。
通过对象序列化可以实现对象的持久化及网络通信功能。
//代码11
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("D:/data1")));
//系列化基本数据类型
oos.writeChar('m');
oos.writeBoolean(false);
oos.writeDouble(Math.random());
oos.writeInt(66);
oos.writeUTF("Mekeater");
序列化自定义对象(对象能够序列化,必须实现Serializable标记接口)
User user = new User(18, "mekeater", true);
oos.writeObject(user);
oos.flush();
oos.close();
}
//实现序列化接口的对象
public class User implements Serializable {
private int age;
private String name;
private boolean isMan;
public User() {
}
public User(int age, String name, boolean isMan) {
this.age = age;
this.name = name;
this.isMan = isMan;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isMan() {
return isMan;
}
public void setMan(boolean man) {
isMan = man;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
", isMan=" + isMan +
'}';
}
}
对上述所序列化的二进制文件进行反序列化,恢复对象数据的示例代码如下
//代码12
public static void main(String[] args) throws IOException {
ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("D:/data1")));
//反序列化数据,读取必须和写入顺序一致
System.out.println(ois.readChar());
System.out.println(ois.readBoolean());
System.out.println(ois.readDouble());
System.out.println(ois.readInt());
System.out.println(ois.readUTF());
User user = (User)ois.readObject();
System.out.println(user.getAge());
System.out.println(user.getName());
System.out.println(user.isMan());
ois.close();
}
字符流
文件字符读(输入)写(输出)流
FileWriter类是Writer抽象类的子类,它实现将数据以字符为单位写入文件。
//代码13
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:/2.txt");//如果文件存在,则默认覆盖
//如需追加需要设置参数
//FileWriter fw = new FileWriter("D:/2.txt",true);
fw.write("hello IO Stream\r\n");//换行
fw.write("Mekeater come on!");
fw.flush();
fw.close();
}
FileReader类是Reader抽象类的子类,它实现将以字符为单位读取文件内容
//代码14
public static void main(String[] args) throws IOException {
FileReader frd = new FileReader("D:/2.txt");
int temp=0;
while ((temp=frd.read())!=-1)
{
System.out.println((char) temp);
}
frd.close();
}
基于缓冲区的文件字符读写流(高效)
与上述基于缓冲区的文件字节读写流思想一致。
文件字符流通常是逐个字符读写内容,效率较低,我们可以通过开辟一块空间(数组)每次将读写的数据装满该空间,达到一次读取或者写出多个字符的效果,进而提高读写效率。
逐个字符读写内容,实现文件拷贝功能
//代码15
//通过字符流实现(但这是一个字符一个字符的读写,效率低)
public static void CopyFile(String source, String target) throws IOException {
FileReader fr = new FileReader(source);
FileWriter fw = new FileWriter(target);
int temp=0;
while ((temp=fr.read())!=-1)
{
fw.write(temp);
}
fw.flush();
fr.close();
fw.close();
}
通过缓冲机制
//代码16
//通过字符流实现(通过缓冲区提高读写效率)
public static void CopyFileBuffer(String source, String target) throws IOException {
FileReader fr = new FileReader(source);
FileWriter fw = new FileWriter(target);
int temp=0;
char[] buffer = new char[1024];//这个长度只能自己指定,不能像字节流可以获取大概的总长度
while ((temp=fr.read(buffer))!=-1)
{
fw.write(buffer,0,temp);
}
fw.flush();
fr.close();
fw.close();
}
BufferedReader类及BufferedWriter类两个处理流,实现缓冲区的思想
//代码17
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("D:/2.txt");//节点流
BufferedWriter bw= new BufferedWriter(fw);//缓冲处理流
bw.write("BufferedWrite context");
bw.newLine();
bw.write("I am Mekeater");
bw.flush();
bw.close();
fw.close();
}
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:/1.txt");//节点流
BufferedReader br = new BufferedReader(fr);//处理流
String temp="";
while ((temp=br.readLine())!=null)
System.out.println(temp);
br.close();
fr.close();
}
转换流
有时候我们能够方便的获取字节流对象,但是我们需要将字节流转为字符流
如我们可以通过System.in获取用户输入的键盘数据,System.out向控制台输出用户输入的数据,但是System.in和System.out返回的都是字节流对象,而我们需要将字节流转为字符流进行操作更为方便,Java IO提供了InputStreamReader类实现输入字节流转为读取字符流,OutputStreamWriter类实现输出字节流转为写出字符流
//代码18
public static void main(String[] args) throws IOException {
//InputStreamReader将字节输入流转为字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//OutputStreamWriter将字节输出流转为字符输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String line="";
while (true)
{
bw.write("请输入:");
bw.flush();
line=br.readLine();
if (line.equals("exit"))
break;
bw.write(line);
bw.newLine();
bw.flush();
}
}
File类
操作文件常用方法
public static void main(String[] args) throws IOException {
File file = new File("D:/2.txt");//连接文件
System.out.println(file.createNewFile());//创建文件(若存在,则默认覆盖,不存在,则创建)
System.out.println(file.exists());//判断文件是否存在
System.out.println(file.getName());//获取文件名
System.out.println(file.getAbsolutePath());//获取文件的绝对路径
System.out.println(file.isHidden());//判断文件是否为隐藏文件
System.out.println(file.delete());//删除文件
}
操作目录常用方法
public static void main(String[] args) throws IOException {
File file = new File("D:/a");//连接目录
System.out.println(file.mkdir());//创建单级目录
File file1 = new File("D:/a/b/c");
System.out.println(file1.mkdirs());//创建多级目录
System.out.println(file.isFile());//判断是否为文件
System.out.println(file.isDirectory());//判断是否为目录
System.out.println(file1.getParent());//获取目录的上一级目录路径
File file2 = new File("D:/");
String[] list = file2.list();//获取目录下的所有文件名
for (String s : list) {
System.out.println(s);
}
System.out.println("=====================");
File[] files = file2.listFiles();//获取目录下的所有文件对应的File类
for (File file3 : files) {
System.out.println(file3.getAbsolutePath());//获取目录下的所有文件的绝对路径
}
}
原文连接:https://blog.csdn.net/qq_34720818/article/details/125840972
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!