当前位置: 首页 > article >正文

Java基础--输入输出

输入/输出类库

流是指在计算机的输入与输出之间的数据的序列,而Java中的数据流有 字节流字符流之分;

就流的运动方向而言,流可分为输入流(input stream)和输出流(output stream),输入流代表从外设流入计算机的数据序列;输出流代表从计算机流向外设的数据序列。流、程序、外设之间的关系如下图:
在这里插入图片描述

一、概述

在Java中,输入输出流用于实现程序与外部数据源(如文件、网络连接等)之间的数据传输。最基本的流类有字节流 InputStream(输入流)和 OutputStream(输出流),以及字符流 Reader(输入字符流)和 Writer(输出字符流)。字节流以字节为单位处理数据,适用于各种二进制数据的读写;字符流则以字符为单位,更适合处理文本数据,尤其是涉及多字节字符(如汉字)的情况。

二、InputStream 类(字节输入流)

read() 方法

  • public int read():从输入流的当前位置处读入一个字节(8位)的二进制数据,将其转换为 0 - 255 的整型量返回。若输入流当前位置无数据了,则返回 -1,表示已读到流的末尾。例如,读取一个简单的二进制文件时,可以通过不断调用该方法逐个字节获取文件内容:
InputStream inputStream = new FileInputStream("example.bin");
int data;
while ((data = inputStream.read())!= -1) {
    // 对读取到的字节数据进行处理,比如存储到其他数据结构中
}
inputStream.close();
  • public int read(byte b[]):从输入流当前位置连续读入多个字节,将其保存到 byte 型数组 b 中,并返回实际读入的字节数。例如,一次读取一定数量字节到数组中:
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FileReadExample {
    public static void main(String[] args) {
        byte[] buffer = new byte[1024];

        // 使用 try-with-resources 自动关闭 InputStream
        try (InputStream inputStream = new FileInputStream("example.txt")) {
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                // 处理读取到的字节数据块
                // 例如,将其转换为字符串(注意:这里只是简单示例,实际转换可能需要更多处理)
                String data = new String(buffer, 0, bytesRead);
                System.out.print(data);
            }
        } catch (IOException e) {
            e.printStackTrace();
            // 可以添加更多的错误处理逻辑
        }
        inputStream.close();
    }
}

内部指针

每个 InputStream 流对象都有一个内部指针,初始时位于流的第一个数据处。每当读入一个字节,指针自动后移一个字节,始终指向未被读取的下一个数据位置,用于确定下次读取数据的起始点。

close() 方法

使用完输入流后,必须调用 close() 方法关闭流,以断开 Java 程序与外设数据源的连接,释放相关系统资源,避免资源泄露。

InputStream 子类的继承关系及特点

  • FileInputStream:用于从文件中读取字节数据,可指定文件路径来创建实例,常用于读取本地文件内容。
  • FilterInputStream:是装饰类的抽象超类,可对其他输入流进行功能增强,比如添加缓冲等功能,其子类有 BufferedInputStream 等。
  • DataInputStream:允许从输入流中读取基本数据类型(如 intdouble 等)以及 String 类型的数据,不过读取时要按照写入的顺序来进行读取操作。
  • BufferedInputStream:为输入流添加缓冲功能,减少与底层数据源的频繁交互,提高读取效率,通常会结合其他输入流一起使用,如 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("file.txt"));

三、OutputStream 类(字节输出流)

write() 方法

  • public void write(int b):将参数 b 的低位字节写入到输出流。例如,向一个字节输出流写入单个字节数据:
OutputStream outputStream = new FileOutputStream("output.bin");
outputStream.write(65); // 写入 ASCII 码为 65 的字符 'A'
outputStream.close();
  • public void write(byte b[]):将 byte 型数组 b 中的全部字节顺序写入到输出流,可用于批量写入字节数据,比如将一个缓冲区中的数据一次性写入文件等:
byte[] data = "Hello, World!".getBytes();
OutputStream outputStream = new FileOutputStream("output.txt");
outputStream.write(data);
outputStream.close();

flush() 方法

对于具备缓冲功能的子类(如 BufferedOutputStream),write() 方法所写的数据先存放在流的缓冲区中,等到缓冲区满了才统一向外设执行写操作。但有时需要在缓冲区未满时就将数据写到外设中,这时就要调用 flush() 方法强制清空缓冲区,把现有数据立即写入外设。例如,在网络传输中,及时发送部分数据时可能就需要调用 flush() 方法。

close() 方法

InputStreamclose() 方法类似,使用完输出流后调用此方法关闭流,释放资源,断开与外设数据源的连接。

OutputStream 子类的继承关系及特点

  • FileOutputStream:用于将字节数据写入文件,可指定文件路径和创建模式(如覆盖原有文件或追加内容等)来创建实例,实现向文件写入内容的功能。
  • FilterOutputStream:也是装饰类的抽象超类,用于增强其他输出流功能,像 PrintStream 等是其子类。
  • PrintStream:常用于输出格式化的文本数据,它提供了方便的 print()println() 方法,可将各种基本数据类型和对象转换为字符串并输出,默认会自动刷新缓冲区(autoFlush 属性设置为 true),常用来输出到控制台(System.out 就是 PrintStream 类型)。
  • DataOutputStream:允许将基本数据类型(如 intdouble 等)以及 String 类型的数据按照特定格式写入到输出流中,方便后续按相应格式读取。

四、Reader 类(字符输入流)

  1. read() 方法

public int read():从输入流的当前位置读入一个字符,并将其作为 int 类型返回(实际返回的是字符对应的 Unicode 码值),若当前位置无数据则返回 -1。如果读取过程中出现错误,会抛出 IOException 类异常。例如,读取一个文本文件中的字符:

Reader reader = new FileReader("example.txt");
int ch;
while ((ch = reader.read())!= -1) {
    char character = (char) ch;
    // 对读取到的字符进行处理,比如判断、拼接等操作
}
reader.close();

public int read(char array[]):从输入流当前位置连续读入多个字符,保存到 char 型数组 array 中,并返回实际读入的字符数。例如,一次读取多个字符到数组中:

char[] buffer = new char[1024];
Reader reader = new FileReader("example.txt");
int charsRead = reader.read(buffer);
while (charsRead!= -1) {
    // 处理读取到的字符数组内容,比如输出到控制台等
    charsRead = reader.read(buffer);
}
reader.close();
  1. 定位指针的方法:每个字符流有一个指针,初始位于流的第一个字符处,每读入一个字符,指针自动后移一个字符位置,指向未被读取的下一个字符。并且提供了一些控制指针位置的方法,如 skip(long n) 可将指针从当前位置向后跳动 n 个字节;mark() 能在指针位置做一个标记;reset() 可将指针移动到 mark() 标记的位置,方便在流中进行有回溯需求的读取操作。

  2. close() 方法:同字节流的 close() 方法作用一样,使用完 Reader 类的输入流后要调用此方法关闭流,释放资源,断开与外设数据源的连接。

  3. Reader 子类的继承关系及特点

  • BufferedReader:为字符输入流添加缓冲功能,提高读取效率,还提供了方便的 readLine() 方法,可一次读取一行文本(以换行符为分隔),常用于按行读取文本文件内容,比如:
BufferedReader br = new BufferedReader(new FileReader("example.txt"));
String line;
while ((line = br.readLine())!= null) {
    // 处理每行文本内容
}
br.close();
  • InputStreamReader:是字节流到字符流的桥梁,可将 InputStream 转换为 Reader,通常用于处理一些底层是字节流但想按字符方式读取的情况,比如从网络输入流中读取文本数据时可能会用到。
  • FileReader:用于从文件中读取字符数据,它内部其实是基于 FileInputStreamInputStreamReader 来实现的,构造时只需指定文件路径即可简单地读取文本文件内容。

五、Writer 类(字符输出流)

  1. Writer 子类的继承关系及特点
    • PrintWriter:提供了方便的 print()println() 方法用于输出格式化的文本数据,可将各种基本数据类型和对象转换为字符串输出,并且支持自动刷新缓冲区等功能,常用来向控制台或文件输出文本内容,比如:
PrintWriter pw = new PrintWriter(new FileWriter("output.txt"));
pw.println("This is a test.");
pw.close();
  • BufferedWriter:为字符输出流添加缓冲功能,减少与底层外设的频繁交互,提高写入效率,它提供了 newLine() 方法用于输出换行符,例如:
BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"));
bw.write("First line");
bw.newLine();
bw.write("Second line");
bw.close();
  • OutputStreamWriter:是字符流到字节流的桥梁,可将字符流转换为字节流输出,常用于将字符数据按特定编码格式写入到底层字节流对应的外设中,比如指定编码将字符写入文件等情况。
  • FileWriter:用于将字符数据写入文件,可指定文件路径和创建模式来创建实例,实现向文件写入文本内容的功能,其内部是基于 OutputStreamWriterFileOutputStream 来实现的。

输入

从控制台读取用户输入(标准输入)

  1. 使用 Scanner 类(常用方式)Scanner 类位于 java.util 包中,它提供了方便的方法来读取不同类型的数据。

示例代码,读取整数、字符串等不同类型数据:

import java.util.Scanner;

public class InputExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入一个整数:");
        int num = scanner.nextInt();
        System.out.println("你输入的整数是: " + num);

        System.out.println("请输入一个字符串:");
        String str = scanner.next();
        System.out.println("你输入的字符串是: " + str);

        scanner.close();
    }
}
  • 首先需要创建一个 Scanner 对象,并将 System.in(标准输入流,代表控制台输入)传递给它。
  • 通过 nextInt() 方法可以读取用户输入的整数,next() 方法可以读取以空白字符(空格、制表符、换行符等)为分隔的下一个字符串。除此之外,还有 nextDouble() 用于读取双精度浮点数,nextBoolean() 用于读取布尔值等,能满足多种类型数据的读取需求。
  • 注意在使用完 Scanner 后,建议调用 close() 方法关闭它,以释放相关资源。

获取特定类型数据的方法,可以查看手册:
在这里插入图片描述
Scanner 类中提供了获取 byte\short\int\long\float\double \boolean\String类型变量的方法。

注意:没有提供获取char类型变量的方法。需要使用next().charAt(0)进行获取。

IDEA快捷用法:这里在补全输入类型时使用的快捷键是 Alt + Enter(注意,要写完;后再使用快捷键进行补齐类型)
在这里插入图片描述

  1. 使用 BufferedReader 类(更高效但稍复杂些)BufferedReader 结合 InputStreamReader 可以实现从控制台读取输入。

示例代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BufferedReaderExample {
    public static void main(String[] args) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        try {
            System.out.println("请输入一个字符串:");
            String str = reader.readLine();
            System.out.println("你输入的字符串是: " + str);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 先通过 InputStreamReader 将标准输入流 System.in 转换为字符流,再用 BufferedReader 对其进行缓冲,提高读取效率。
  • 使用 readLine() 方法读取一行字符串,不过它会抛出 IOException,所以需要放在 try-catch 块中来处理可能出现的异常情况。

从文件读取输入

  1. 使用 FileReaderBufferedReader 组合(按字符读取文件内容)

示例代码如下,用于读取一个文本文件的内容:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileInputExample {
    public static void main(String[] args) {
        try {
            BufferedReader reader = new BufferedReader(new FileReader("example.txt"));
            String line;
            while ((line = reader.readLine())!= null) {
                System.out.println(line);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 首先创建 FileReader 对象,指定要读取的文件路径(这里假设 example.txt 在当前项目目录下,如果文件在其他目录需要写全路径),它用于将文件以字符流的形式打开。
  • 然后将 FileReader 传递给 BufferedReader 来缓冲字符流,提升读取效率。
  • 通过循环调用 readLine() 方法逐行读取文件内容,直到读取到 null,表示文件末尾,同时要注意在 try-catch 块中处理 IOException 异常。
  1. 使用 FileInputStreamBufferedInputStream 组合(按字节读取文件内容)

这种方式适合处理二进制文件等需要按字节读取的情况,示例代码:

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class ByteFileInputExample {
    public static void main(String[] args) {
        try {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("example.bin"));
            int data;
            while ((data = bis.read())!= -1) {
                System.out.print((char) data);
            }
            bis.close();
            // 注意这里直接将字节转为字符输出可能存在问题,若为非文本文件结果会乱码,实际中按需处理数据
            // 比如对于图片等二进制文件,可进行相应的字节处理,而非转为字符输出
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 创建 FileInputStream 对象用于打开文件的字节流,然后将其传递给 BufferedInputStream 进行缓冲。
  • 通过循环调用 read() 方法逐字节读取文件内容,返回值为 -1 时表示读到文件末尾,同样需要在 try-catch 块中处理 IOException 异常。

从命令行输入

编写一个应用程序求若干个数的平均数,原始数字要求从命令行输入。应用程序中main方法的参数String类型的数组args能接受用户从命令行键入的参数。

public class Test
{
    public static void main(String args[])
    {
        double n, sum = 0;
        for (int i = 0; i < args.length; i++) {
            sum += Double.valueOf(args[i]);
        }
        n = sum / args.length;
        System.out.println("average=" + n);
    }
}

注意:

  • 参数的个数可以利用 args.length来取得。
  • 参数 “12.34”、“34.45”、“21212121”分别赋给了main方法的参数arges[0]、arges[1]和arges[2]。
  • 由于arges[0]、arges[1]和arges[2]是String类型的,所以要利用Double.valueOf(String s)方法将String类型转化成Double类型。

在IDEA中(这里我是的版本是 IntelliJ IDEA 2022.2.3),使用命令行执行代码的步骤:
方法一:
在这里插入图片描述

  • 点击下方选项卡中的Terminal(终端),进入你要编译运行Java源文件的路径下(在默认情况下,终端初始路径就是IDEA打开工程的路径),使用 cd命令 + 路径名 的方式进入目标目录。

  • 切换到正确目录后,在命令行中输入以下命令来编译代码:javac Test.java;如果代码没有语法错误,编译成功后会在同一目录下生成 Test.class 文件。
    在这里插入图片描述

  • 在编译成功后,就可以执行代码:java Test 1.5 2.5 3.0(注意,你的源文件放在一个包文件下,编译器会自动添加包含这个包文件的语句,如我的Test源文件在experiment包下,在首行会为我自动添加package experiment;,但是在使用命令行进行编译运行时,不能包含这个这个语句,否则会出现错误: 找不到或无法加载主类 Test。所以在编译之前可以将该语句注释掉重新编译运行即可。当然如果这个源文件不在一个包下,就没有上述问题)

方法二:
在这里插入图片描述
使用首部选项卡中的Run下的Run/Debug Configurations:
在这里插入图片描述
然后直接运行即可。

输出

输出到控制台(标准输出)

  1. 使用 System.out.println()System.out.print()(常用方式)System.out.println() 用于输出内容后自动换行,例如:
System.out.println("Hello, World!");  // 输出 Hello, World! 并换行

System.out.print() 只输出内容,不会自动换行,例如:

System.out.print("Hello");
System.out.print(" World!");  // 输出 Hello World! 在同一行
  1. 使用 System.out.printf()(格式化输出,类似C语言的 printf

它可以按照指定的格式来输出数据,示例:

int num = 10;
double d = 3.14;
System.out.printf("整数是: %d,小数是: %.2f\n", num, d);
// 按照格式输出,%d 表示整数格式,%f 表示浮点数格式,%.2f 表示保留两位小数的浮点数格式

输出到文件

  1. 使用 FileWriterBufferedWriter 组合(按字符写入文件)

示例代码,用于将一些内容写入到文本文件中:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FileOutputExample {
    public static void main(String[] args) {
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"));
            writer.write("这是要写入文件的内容");
            writer.newLine();  // 写入换行符
            writer.write("第二行内容");
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 先创建 FileWriter 对象,指定要写入的文件路径(如果文件不存在会自动创建,若存在则覆盖原内容),它将内容以字符流的形式准备写入文件。
  • 再将 FileWriter 传递给 BufferedWriter 进行缓冲处理,提高写入效率。
  • 通过 write() 方法写入内容,newLine() 方法写入换行符,最后记得关闭 writer 以确保内容正确写入文件并释放资源。
  1. 使用 FileOutputStreamBufferedOutputStream 组合(按字节写入文件)

适用于写入二进制文件等情况,示例代码:

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteFileOutputExample {
    public static void main(String[] args) {
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("output.bin"));
            byte[] data = {65, 66, 67};  // 示例字节数据,比如可以是图片等二进制文件的部分字节
            bos.write(data);
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
  • 创建 FileOutputStream 对象用于打开文件的字节流通道,然后将其传递给 BufferedOutputStream 进行缓冲。
  • 通过 write() 方法将字节数组等字节数据写入文件,最后关闭输出流确保数据写入并释放资源。

TIP: 获取一个[a,b]范围的随机整数

int num = (int)(Math.random() + (b - a +1)) + a;

http://www.kler.cn/a/410479.html

相关文章:

  • 【Python】分割秘籍!掌握split()方法,让你的字符串处理轻松无敌!
  • springboot获取配置文件中的值
  • 论文阅读:A fast, scalable and versatile tool for analysis of single-cell omics data
  • strupr(arr);模拟实现(c基础)
  • Otter 安装流程
  • JavaScript将至
  • STM32 Keil5 attribute 关键字的用法
  • Java爬虫:数据采集的强大工具
  • Perl 简介
  • react函数式组件中的路由传参方式
  • 智慧环保大数据解决方案
  • 如何防止序列化破坏单例模式
  • 探索C/C++的奥秘之stack和queue
  • Python 数据分析核心库大全!
  • 《Python游戏编程入门》注-第8章5
  • go语言range的高级用法-使用range来接收通道里面的数据
  • spark 3.4.4 利用Spark ML中的交叉验证、管道流实现鸢尾花分类预测案例选取最优模型
  • 【zookeeper03】消息队列与微服务之zookeeper集群部署
  • 网络新技术新应用在网络安全领域的发展特点
  • 【GL004】Linux
  • vue3 reactive响应式实现源码
  • CTO 实际上是做什么的?
  • IP Transit國外頻寬使用最高優先權,國內直接與骨幹互連
  • archlinux 触摸板手势配置
  • crmeb 分享商品 邀请码 bug 修复 记录
  • java学习记录12