首页 > 编程语言 >JavaSE中的IO(输入/输出)字节流字符流

JavaSE中的IO(输入/输出)字节流字符流

时间:2024-06-11 15:31:36浏览次数:27  
标签:字符 java 字节 文件 IO new JavaSE txt

JavaSE中的IO(输入/输出)知识是一个广泛的领域,它涵盖了如何在Java程序中进行数据的读取和写入。以下是对JavaSE中IO知识的一个清晰归纳:

一、基础知识

流(Stream)的概念

在这里插入图片描述

流是一组有顺序的、有起点和终点的字节集合,用于数据传输。Java的I/O流提供了读写数据的标准方法。Java的I/O流分为输入流(从其他设备读取数据到内存)和输出流(从内存写出数据到其他设备)。

字节流与字符流

字节流:以字节为单位,读写数据的流。例如,InputStream和OutputStream是字节流的抽象类。
字符流:以字符为单位,读写数据的流。例如,Reader和Writer是字符流的抽象类。

主要类和方法

1. InputStream

字节输入流的抽象类,包含read(), read(byte[] b), close()等方法。下面是一个java代码的示例,说明了InputStream的read()、read(byte[] b)和close()方法的用法:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileInputStream对象
            InputStream inputStream = new FileInputStream("example.txt");

            // 使用read()方法逐个字节读取文件内容并打印
            int data;
            while ((data = inputStream.read()) != -1) {
                System.out.print((char) data);
            }

            // 关闭输入流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们创建了一个FileInputStream对象来读取名为"example.txt"的文件。然后,使用read()方法逐个字节地读取文件内容,直到读取到文件的末尾(返回-1)。每次读取的字节数据都会被转换为字符并打印出来。

下面是另一个示例,演示了使用read(byte[] b)方法从InputStream中读取多个字节到一个字节数组中:

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class InputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileInputStream对象
            InputStream inputStream = new FileInputStream("example.txt");

            // 创建一个byte数组用于存储读取的数据
            byte[] buffer = new byte[1024];

            // 使用read(byte[] b)方法读取文件内容并打印
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                System.out.write(buffer, 0, bytesRead);
            }

            // 关闭输入流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们创建了一个大小为1024的字节数组作为缓冲区。然后,使用read(byte[] b)方法从输入流中读取数据,将读取的字节数保存到bytesRead变量中。接下来,通过System.out.write()方法将读取到的数据以字符的形式打印出来。

最后,我们使用close()方法关闭输入流,确保资源被正确释放。

2.OutputStream

字节输出流的抽象类,包含write(int b), write(byte[] b), close(), flush()等方法。下面是一个java代码的示例,说明了OutputStream的write(int b),write(byte[] b),close()和flush()方法的用法:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class OutputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileOutputStream对象
            OutputStream outputStream = new FileOutputStream("example.txt");

            // 使用write(int b)方法将单个字节写入文件
            outputStream.write(65); // 写入字母"A"

            // 使用write(byte[] b)方法将字节数组写入文件
            byte[] buffer = {66, 67, 68}; // 字节数组包含字母"B"、"C"和"D"
            outputStream.write(buffer);

            // 关闭输出流
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们创建了一个FileOutputStream对象来写入名为"example.txt"的文件。然后,使用write(int b)方法将单个字节写入文件。这里使用了ASCII码值65,代表字母"A"。接下来,使用write(byte[] b)方法将字节数组写入文件。字节数组包含ASCII码值为66、67和68的字节,分别对应字母"B"、“C"和"D”。

最后,我们使用close()方法关闭输出流,确保资源被正确释放。

另外,OutputStream还有一个flush()方法,用于强制将缓冲区中的数据写入到输出流中。下面是一个示例:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class OutputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileOutputStream对象
            OutputStream outputStream = new FileOutputStream("example.txt");

            // 使用write()方法将字节写入缓冲区
            outputStream.write(65); // 写入字母"A"

            // 使用flush()方法强制将缓冲区中的数据写入输出流
            outputStream.flush();

            // 关闭输出流
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这个示例中,我们写入了字母"A"到输出流的缓冲区中,然后使用flush()方法将缓冲区中的数据强制写入输出流。

这些是OutputStream的基本用法,可以通过这些方法将字节写入到输出流中。

3.Reader和Writer

分别为字符输入流和字符输出流的抽象类,提供了类似字节流的方法,但操作的是字符。下面是一个java代码的示例,说明了Reader和Writer的基本用法:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;

public class ReaderWriterExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileReader对象来读取文件
            Reader reader = new FileReader("input.txt");

            // 创建一个FileWriter对象来写入文件
            Writer writer = new FileWriter("output.txt");

            // 使用read()方法逐个字符读取文件内容并写入输出文件
            int character;
            while ((character = reader.read()) != -1) {
                writer.write(character);
            }

            // 关闭输入和输出流
            reader.close();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的例子中,我们创建了一个FileReader对象来读取名为"input.txt"的文件。然后,我们创建了一个FileWriter对象来写入名为"output.txt"的文件。使用read()方法逐个字符地读取输入文件的内容,并使用write()方法将字符写入输出文件。

最后,我们使用close()方法关闭输入和输出流,确保资源被正确释放。

这些是Reader和Writer的基本用法,可以通过这些方法进行字符的输入和输出操作。

二、常用子类

1.文件流

FileInputStream和FileOutputStream:用于从文件和向文件读写字节。
FileReader和FileWriter:用于从文件和向文件读写字符。
字节流适用于处理二进制数据,字符流适用于处理文本数据。对于文本数据,推荐使用字符流,因为字符流可以自动处理字符编码的转换,而字节流需要手动进行编码和解码操作。
下面是一个Java代码示例,分别使用FileInputStream、FileOutputStream、FileReader和FileWriter来读写字节和字符:

使用FileInputStream和FileOutputStream读写字节:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileInputStreamExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileInputStream对象来读取文件
            FileInputStream fis = new FileInputStream("input.txt");

            // 创建一个FileOutputStream对象来写入文件
            FileOutputStream fos = new FileOutputStream("output.txt");

            // 使用read()方法读取字节,并使用write()方法写入字节
            int data;
            while ((data = fis.read()) != -1) {
                fos.write(data);
            }

            // 关闭输入和输出流
            fis.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用FileReader和FileWriter读写字符:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileReaderWriterExample {
    public static void main(String[] args) {
        try {
            // 创建一个FileReader对象来读取文件
            FileReader fr = new FileReader("input.txt");

            // 创建一个FileWriter对象来写入文件
            FileWriter fw = new FileWriter("output.txt");

            // 使用read()方法读取字符,并使用write()方法写入字符
            int data;
            while ((data = fr.read()) != -1) {
                fw.write(data);
            }

            // 关闭输入和输出流
            fr.close();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在这两个例子中,我们使用了不同的输入流和输出流来进行字节和字符的读写操作。在读取文件时,我们使用read()方法读取每个字节或字符,并使用write()方法将字节或字符写入输出文件。

最后,我们使用close()方法关闭输入和输出流,确保资源被正确释放。

这些是使用FileInputStream、FileOutputStream、FileReader和FileWriter进行字节和字符读写的基本示例。

2.缓冲流

BufferedInputStream和BufferedOutputStream:提供了带缓冲区的字节流,可以提高读写效率。
BufferedReader和BufferedWriter:提供了带缓冲区的字符流。

下面我将用代码举例说明如何使用BufferedInputStream和BufferedOutputStream以及BufferedReader和BufferedWriter。

  1. 使用BufferedInputStream和BufferedOutputStream从文件中读取和写入字节:
import java.io.*;

public class BufferedStreamExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile))) {

            int bufferSize = 1024;
            byte[] buffer = new byte[bufferSize];
            int bytesRead;

            while ((bytesRead = bis.read(buffer, 0, bufferSize)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }

            System.out.println("File copied successfully!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,我们使用BufferedInputStream从名为"source.txt"的文件中读取字节,并使用BufferedOutputStream将字节写入名为"target.txt"的文件中。我们使用了一个内部缓冲区,大小为1024字节,并循环读取和写入缓冲区中的字节。

  1. 使用BufferedReader和BufferedWriter从文件中读取和写入字符:
import java.io.*;

public class BufferedWriterExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
             BufferedWriter writer = new BufferedWriter(new FileWriter(targetFile))) {

            String line;

            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine();
            }

            System.out.println("File copied successfully!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,我们使用BufferedReader从名为"source.txt"的文件中读取字符,并使用BufferedWriter将字符写入名为"target.txt"的文件中。我们循环读取每一行字符,并将其写入目标文件。我们使用了一个内部缓冲区来提高读写效率,并使用writer.newLine()方法在每个写入行的末尾添加一个换行符。

这些示例演示了如何使用缓冲流来提高读写操作的效率,并且适用于处理字节和字符数据。请注意,使用完缓冲流后,我们需要及时关闭它们,以确保资源被释放。以上示例中使用了try-with-resources语句,可以在不需要显式关闭流的情况下自动关闭它们。

3.转换流

InputStreamReader和OutputStreamWriter:用于在字节流和字符流之间进行转换。

InputStreamReader是将字节流转换为字符流的桥梁。它读取字节并使用指定的字符编码将其转换为字符。它提供了读取字符的方法,比如read()和readLine()。

OutputStreamWriter则是将字符流转换为字节流的桥梁。它将字符写入输出流,并使用指定的字符编码将其转换为字节。它提供了写入字符的方法,比如write()和flush()。

下面是一个示例,展示如何使用InputStreamReader和OutputStreamWriter进行字节流和字符流的转换:

import java.io.*;

public class InputStreamReaderExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";

        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(targetFile);
             InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
             OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8")) {

            int c;

            while ((c = isr.read()) != -1) {
                osw.write(c);
            }

            System.out.println("File converted successfully!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在上面的示例中,我们使用FileInputStream从名为"source.txt"的文件中读取字节。然后,我们使用InputStreamReader将字节流转换为字符流,并指定了字符编码为UTF-8。接着,我们使用FileOutputStream将字符流转换为字节流,并指定了字符编码为UTF-8。最后,我们使用OutputStreamWriter将字符写入名为"target.txt"的文件中。

请注意,示例中的try-with-resources语句用于自动关闭流。此外,我们还可以在InputStreamReader和OutputStreamWriter的构造函数中指定其他的字符编码,以根据实际需求进行转换。

三、其他重要概念

1.编码:

不同的编码方式会影响字符和字节之间的转换。常见的编码方式有GBK、UTF-8、UTF-16等。

2.File类:

java.io.File类用于表示文件或目录,提供了许多操作文件和目录的方法,如创建、删除、判断是否存在等。
当使用File类时,我们可以使用下面的几个例子来说明它的用法:

  1. 创建文件:
File file = new File("path/to/file.txt");
try {
  boolean created = file.createNewFile();
  if (created) {
    System.out.println("文件创建成功!");
  } else {
    System.out.println("文件已存在!");
  }
} catch (IOException e) {
  e.printStackTrace();
}
  1. 创建目录:
File dir = new File("path/to/directory");
boolean created = dir.mkdir();
if (created) {
  System.out.println("目录创建成功!");
} else {
  System.out.println("目录已存在!");
}
  1. 删除文件:
File file = new File("path/to/file.txt");
boolean deleted = file.delete();
if (deleted) {
  System.out.println("文件删除成功!");
} else {
  System.out.println("文件不存在或删除失败!");
}
  1. 判断文件是否存在并获取文件属性:
File file = new File("path/to/file.txt");
if (file.exists()) {
  System.out.println("文件存在!");
  System.out.println("文件路径:" + file.getPath());
  System.out.println("文件大小:" + file.length() + "字节");
  System.out.println("最后修改时间:" + new Date(file.lastModified()));
} else {
  System.out.println("文件不存在!");
}
  1. 重命名文件:
File file = new File("path/to/file.txt");
File renamedFile = new File("path/to/renamedFile.txt");
boolean renamed = file.renameTo(renamedFile);
if (renamed) {
  System.out.println("文件重命名成功!");
} else {
  System.out.println("文件重命名失败!");
}

RandomAccessFile类:
RandomAccessFile类是Java提供的一个用于随机访问文件的类。它既可以读取文件内容,也可以向文件中写入数据,并且可以在文件中定位到指定的位置进行读写操作。

下面是一些RandomAccessFile类的例子:

  1. 读取文件内容:
RandomAccessFile raf = new RandomAccessFile("path/to/file.txt", "r");
byte[] buffer = new byte[1024];
int bytesRead = raf.read(buffer);
String contents = new String(buffer, 0, bytesRead);
System.out.println("文件内容:" + contents);
raf.close();
  1. 向文件中写入数据:
RandomAccessFile raf = new RandomAccessFile("path/to/file.txt", "rw");
String data = "Hello, world!";
raf.write(data.getBytes());
raf.close();
System.out.println("数据已写入文件!");
  1. 定位到指定位置进行读写操作:
RandomAccessFile raf = new RandomAccessFile("path/to/file.txt", "rw");
raf.seek(10); // 定位到文件的第10个字节处
byte[] buffer = new byte[1024];
int bytesRead = raf.read(buffer);
String contents = new String(buffer, 0, bytesRead);
System.out.println("文件内容:" + contents);
raf.close();

RandomAccessFile类还提供了其他方法,如获取文件长度、设置文件指针位置、截取文件等。通过使用RandomAccessFile类,你可以更灵活地读取和写入文件的内容,并且可以随时定位到文件的任意位置进行操作。

3.序列化与反序列化:

序列化和反序列化是Java中用于对象持久化和网络传输的重要概念。

序列化(Serialization)是指将对象转换为字节序列的过程,可以将对象保存在磁盘中或通过网络进行传输。在序列化过程中,对象的状态信息被转换为字节数据,可以包括对象的属性值、方法等信息。Java中的序列化由java.io.Serializable接口实现,只有实现了该接口的类才能被序列化。

下面是一个简单的示例,展示了如何将一个对象进行序列化:

import java.io.*;

public class SerializationExample {
    public static void main(String[] args) {
        // 创建一个对象
        Person person = new Person("John", 25);

        try {
            // 创建一个输出流,并将对象进行序列化
            FileOutputStream fileOut = new FileOutputStream("person.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();
            System.out.println("对象已序列化并保存在 person.ser 文件中");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class Person implements Serializable {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

反序列化(Deserialization)是指将字节序列恢复为对象的过程。反序列化可以从磁盘文件或网络传输的字节流中恢复出对象的状态信息,并创建一个对象实例。Java中的反序列化通过ObjectInputStream类来实现。

下面是一个简单的示例,展示了如何从文件中反序列化一个对象:

import java.io.*;

public class DeserializationExample {
    public static void main(String[] args) {
        Person person = null;

        try {
            // 创建一个输入流,并从文件中读取字节序列反序列化为对象
            FileInputStream fileIn = new FileInputStream("person.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            person = (Person) in.readObject();
            in.close();
            fileIn.close();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return;
        }

        System.out.println("反序列化后的对象:");
        System.out.println("姓名: " + person.getName());
        System.out.println("年龄: " + person.getAge());
    }
}

注意:要进行序列化和反序列化,对象的类必须加上implements Serializable接口,否则会抛出NotSerializableException异常。序列化是将对象转换为字节序列以便存储或传输的过程,反序列化则是将字节序列恢复为对象的过程。

标签:字符,java,字节,文件,IO,new,JavaSE,txt
From: https://blog.csdn.net/m0_61898915/article/details/139598091

相关文章

  • Stable diffusion 再现女皇武则天,SD图文教程
    本次教程使用的是文生图功能本次教程按照从上到下的操作顺序如下:①选好大模型,②输入关键词,③选好LORA模型,④设置出图参数,⑤设置ControlNet大模型:majicMIXrealistic麦橘写实_v7大模型可以在这里搜索,点击加入模型库就行了https://www.liblib.artStablediffus......
  • FFmpeg结构体:AVIOContext
    1.描述AVIOContext是FFmpeg管理输入输出数据的结构体,位于avio.h文件中。2.结构体定义1typedefstructAVIOContext{2/**3*Aclassforprivateoptions.4*5*IfthisAVIOContextiscreatedbyavio_open2(),av_classissetand......
  • C2. Magnitude (Hard Version)
    原题链接题解由于使用操作二会让负数变成正数,所以我们考虑让操作二在c最小且为负数的点使用在使用完操作二之后,之后的c肯定非负,所以在此之后两种操作都可以使用实施先判断存不存在c最小且为负数的点,然后再统计所有c最小且为负数的点的贡献code#include<bits/stdc++.h>usin......
  • linux内存管理(六)- 内核新struct - folio
    folio大概是5.16引入的,看起来像是page的封装,这里有一篇讲解folio很好的博客,论好名字的重要性:Linux内核page到folio的变迁-CSDN博客structfolio{/*private:don'tdocumenttheanonunion*/union{struct{/*public:*/unsignedlon......
  • Auto Arena of LLMs: Automating LLM Evaluations with Agent Peer-battles and Commi
    1.引言大语言模型(LLMs)发展迅速,亟需可靠的评估方法。静态数据集存在污染风险,人工评估平台耗时费力。提出自动、可靠、可信的评估框架:Auto-ArenaofLLMs(Auto-Arena)。2.相关工作自动评估方法:静态数据集和基于模型的评估。人工评估平台:ChatbotArena,存在耗时和语言......
  • Android studio(创建、监听器intent菜单)
    创建报错connectrunout可以查看这篇文章1.自动创建  2.设置输出日志信息logt+tab键之后会为当前的类自动生成一个TAG常量 关于日志过滤器 这时候在只有Log.v里面的消息,Log.d、i、w、e都没有出现。当输入MainActivity的时候过滤到与其相关的 3.手动创建选......
  • AI绘画Stable Diffusion必看:如何生成人物的全身照实战教程!
    大家好,我是画画的小强在小伙伴们私下留言中,关于如何实现人物的全身照一直有人咨询,看来这个问题还是困惑着不少小伙伴,今天我们就这个问题详细讨论一下。一.宽高比参数设置在讨论如何生成图片的全身照之前,我们先来讨论一下StableDiffusion中宽高比的参数设置。这2个参......
  • 一文了解AI绘画两大鼻祖 Midjourney 和 Stable Diffusion的区别,超详细讲解小白入门必
    大家好,我是画画的小强要说AI绘画软件哪家强?有人说Midjoureny(MJ),有人说StableDiffuion(SD),那他们到底有什么区别?应该选择哪款软件学习?今天带大家全面了解一下!文末可白嫖AI资料哦~一.使用费用对比Midjourney的收费为每月8-120美金不等,折算成RMB为60-880左右。分为4......
  • Vision-Language Models are Zero-Shot Reward Models for Reinforcement Learning
    发表时间:2024(ICLR2024)文章要点:文章提出用预训练的视觉语言模型作为zero-shot的rewardmodel(VLM-RMs)。好处在于可以通过自然语言来给定一个具体的任务,通过VLM-RMs让强化学习基于reward学习这个任务(usingpretrainedvision-languagemodels(VLMs)aszeroshotrewardmodels......
  • 苹果iOS 18发布:新增锁屏自定义和应用锁
    今天凌晨1点,iOS18在苹果WWDC24上正式发布。全新的iOS18允许用户自由定义App排列,可以自由选择App颜色主题,并且iOS18升级支持锁屏状态自定义功能,还支持单个App的应用锁,保护用户隐私。与此同时,iOS18对控制中心也进行了升级调整,全新的控制中心更具有扩展性,支持第三方应用控制按......