1. Stream 流
2. File 和 IO
Java.io
包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标:
2.1 控制台输入
Java
的控制台输入由 System.in
完成, 将 System.in
包装在一个 BufferedReader
对象中来创建一个字符流,创建后可使用 read()
方法读取一个 字符,读取字符串使用 readLine()
:
import java.io.*;
public class BufferedReaderTest {
public static void main(String[] args) throws IOException {
char c;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("输入字符,按 'q' 退出:");
do {
// 读取字符
c = (char) br.read(); // 每次只能读取一个字符
System.out.println(c);
} while (c != 'q');
}
}
输出:
输入字符,按 'q' 退出:
a
a
b
b
c
c
java
j
a
v
a
q
q
注意:
read()
方法读取一个字符,就会返回一个整数,直至输入流结束,返回 -1,此时会抛出IOException
,因此要throws
2.2 控制台输出
控制台的输出可以由 print() 和 println() 、write()
完成,都是来自 PrintStream
类,不过 write()
方法不常用:
// void write(int byteval),write() 方法将 byteval 的低八位字节写到流中
System.out.println("abc");
int b;
b = 'A';
System.out.write(b);
System.out.write('\n');
2.3 文件读写
2.3.1 FileInputStream
该流用于读取文件数据,创建方法:
// 方法一
InputStream f = new FileInputStream("xxx.txt");
// 方法二
File f = new File("xxx.txt");
InputStream in = new FileInputStream(f);
文件对象常用方法
方法 | 描述 |
---|---|
public void close() throws IOException{} | 关闭文件输入流并释放与此流相关的所有系统资源,抛出 IOException |
protected void finalize()throws IOException {} | 清除与该文件的连接,确保在不引用时调用 close() 方法,抛出 IOException |
public int read(int r)throws IOException{} | 从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回-1 |
public int read(byte[] r) throws IOException{} | 从输入流读取r.length 长度的字节。返回读取的字节数。如果是文件结尾则返回-1 |
public int available() throws IOException{} | 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值 |
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
readFile();
}
public static void readFile() throws IOException {
int name;
// 创建文件对象
InputStream input = new FileInputStream("F:\\JavaStudy\\Source\\FileTest\\src\\people.txt");
do {
name = input.read(); // 循环调用 read(),直至返回 -1
System.out.println(name);
} while (name != -1); // name = -1 时文件读取完毕
input.close(); // 关闭
}
}
运行结果:
114
111
115
101
13
10
108
105
108
97
13
10
106
111
104
110
-1
read()
方法每次只会读取一个字节,直至读取完毕,返回 -1(可以根据此来作为循环退出条件),另外需要记得关闭文件对象!
使用 for
循环读取:
public static void readFile() throws IOException {
int name;
// 创建文件对象
InputStream input = new FileInputStream("F:\\JavaStudy\\Source\\FileTest\\src\\people.txt");
// do {
// name = input.read(); // 循环调用 read(),直至返回 -1
// System.out.println(name);
// } while (name != -1);
for (; ; ) {
name = input.read(); // 循环调用 read(),直至返回 -1
if (name == -1) {
break;
}
System.out.println(name);
}
input.close(); // 关闭
}
使用 try...finally
保证任何时候都会关闭文件对象:
public static void readFileTest() throws IOException {
InputStream input = null;
try {
input = new FileInputStream("F:\\JavaStudy\\Source\\FileTest\\src\\people.txt");
int n = 0;
while (n != -1) {
n = input.read();
System.out.println(n);
}
} finally {
if (input != null) {
input.close();
}
}
}
Java7
后,省略写法:
public void readFile() throws IOException {
try (InputStream input = new FileInputStream("F:\\JavaStudy\\Source\\FileTest\\src\\people.txt")) {
int n;
while ((n = input.read()) != -1) {
System.out.println(n);
}
} // 编译器在此自动为我们写入finally并调用close()
}
缓冲(一次读取多个字节)
read()
方法只能一次读取一个字节,但是可以将读取的字节放入一个缓冲的 bytes[]
数组中,这样返回值不再是字节的 int
值,而是返回实际读取了多少个字节。如果返回-1,表示没有更多的数据了:
public static void readFileCache() throws IOException {
try (InputStream input = new FileInputStream("F:\\JavaStudy\\Source\\FileTest\\src\\people.txt")) {
// 定义 1000 个字节大小的缓冲区
byte[] buffer = new byte[1000];
int n;
while ((n = input.read(buffer)) != -1) {
System.out.println("已读取:" + n + " 字节!"); // 已读取:16 字节!
}
}
}
2.3.2 FileOutputStream
FileOutputStream
用来创建一个文件并向文件中写数据,若目标文件不存在,那么该流会创建该文件:
// 方法一
OutputStream f = new FileOutputStream("C:/java/hello")
// 方法二
File f = new File("C:/java/hello");
OutputStream fOut = new FileOutputStream(f);
常用方法
方法 | 说明 |
---|---|
close() | 关闭文件对象,释放系统资源 |
finalize() | 清除与该文件的连接,确保在不再引用文件输入流时调用其 close 方法。抛出 IOException 异常 |
write(int w) | 将指定的字节写入到输出流中 |
write(byte[] w) | 将指定数组中的 w.length 长度的字节写入到输出流中 |
flush() | 将缓冲区内容写入输出流中 |
flush()
当向磁盘、网络写入数据时,并不是输出一个字节就立即写入,而是先把输出存入内存中(相当于缓冲区),当到达一定量后(缓冲区满了)再写入磁盘或网络,这能提高写入效率,减少 IO
消耗;flush()
可以强制将缓冲区内容输出,一般情况下我们不需要手动去 flush
(会自动 flush
),除非一些特殊情况需要,比如缓冲区大小 4K,但是输出的字节大小不足 4k,这是就需要手动去 flush()
。
一次写入多个字节 xx.getBytes()
转换为 byte[]
:
public static void writeFile() throws IOException {
try (OutputStream output = new FileOutputStream("F:\\JavaStudy\\Source\\FileTest\\src\\result.txt")) {
output.write("Hello".getBytes("UTF-8"));
}
}
2.4 File 类
关于文件和 IO
的类:
File
:FileReader
:FileWriter
:
创建目录
File
类中两个方法:
mkdir()
:创建一个目录,成功返回true
,否则返回false
(表示指定的路径已存在或整个路径不存在)mkdirs()
:递归创建目录(多个)
import java.io.File;
public class FileTest {
public static void main(String[] args) {
String path = "F:\\JavaStudy\\Source\\FileTest\\src\\newFile";
File d = new File(path);
d.mkdir();
}
}
读取目录
isDirectory()
:是否是一个目录,是返回true
list()
:返回目标目录中所有文件夹和文件
import java.io.File;
public class FileTest {
public static void main(String[] args) {
String path = "F:\\JavaStudy\\Source\\FileTest\\src";
File f1 = new File(path);
if (f1.isDirectory()) {
System.out.println(path + " 是一个目录!");
String[] file_arrs = f1.list();
for (int i = 0; i < file_arrs.length; i++) {
File f2 = new File(file_arrs[i]);
if (f2.isDirectory()) {
System.out.println(file_arrs[i] + " 是一个目录!");
} else {
System.out.println(file_arrs[i] + " 是一个文件!");
}
}
} else {
System.out.println(path + " 是一个文件!");
}
}
}
运行结果:
F:\JavaStudy\Source\FileTest\src 是一个目录!
BufferedReaderTest.java 是一个文件!
FileInputStreamTest.java 是一个文件!
FileTest.java 是一个文件!
newFile 是一个文件!
people.txt 是一个文件!
result.txt 是一个文件!
删除文件或目录
delete()
方法删除目录时,需保证该目录下没有其他文件,否则会删除失败:
import java.io.File;
public class FileTest {
public static void main(String[] args) {
// 删除目录或文件
deleteDirectoryOrFile();
}
public static void deleteDirectoryOrFile() {
String path = "F:\\JavaStudy\\Source\\FileTest\\src\\newFile";
File f1 = new File(path);
// 直接删除失败
// f1.delete();
deleteDirectory(f1);
}
public static void deleteDirectory(File f1) {
File[] files = f1.listFiles();
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
deleteDirectory(f);
} else {
f.delete();
}
}
}
f1.delete();
}
}
其他方法
canRead() // 是否可读
canWrite() // 是否可写
canExecute() // 是否可执行
length() // 文件字节大小
listFiles() // 列出目录下的文件和子目录名
2.5 Path 类
Path
类与 File
类功能相似,但操作更简单,位于 java.nio.file
包中:
public static void getPath() {
Path p1 = Paths.get(".", "project", "java_study"); // 构造一个Path对象
System.out.println(p1); // .\project\java_study
// 转换为绝对路径 F:\JavaStudy\Source\.\project\java_study
Path p2 = p1.toAbsolutePath();
System.out.println(p2);
// 转换为规范路径 F:\JavaStudy\Source\project\java_study
Path p3 = p2.normalize();
System.out.println(p3);
// 转换为File对象 F:\JavaStudy\Source\project\java_study
File f = p3.toFile();
System.out.println(f);
// 遍历Path
for (Path p: Paths.get("..").toAbsolutePath()) {
System.out.println("===>" + p);
/*
===>JavaStudy
===>Source
===>..
*/
}
}
2.6 Scanner 类
Scanner
类可以获得用户输入:
Scanner scan = new Scanner(System.in);
常用方法
next()、nextLine()
:获取输入的字符串hasNext()、hasNextLine()
:是否还有数据输入nextInt()、nextFloat()
:接收数字
2.6.1 接收字符串
next 方法
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入:");
if (scan.hasNext()) {
String str1 = scan.next();
System.out.println(str1);
}
scan.close();
}
}
运行结果:
请输入:
Hello World // 输入的字符串
Hello // 只输出了 Hello,没有输出 World
nextLine()
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入:");
if (scan.hasNextLine()) {
String str2 = scan.nextLine();
System.out.println(str2);
}
scan.close();
}
}
运行结果:
请输入:
Hello World
Hello World
next() 与 nextLine() 区别
next()
- 对录入的字符串遇到 空格就会停止录入,会截断空格后的字符串
- 在录入字符串时,会在尾部加一个
\r\n
,若next
在nextLine
之前录入就会导致nextLine
录入了\r\n
nextLine()
- 会把整行字符串全部录入,录入字符串时推荐使用
- 以 回车为结束符,可获得空白
2.6.2 接收数字
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int m = 0;
float n = 0;
System.out.println("请输入一个整数:");
if (scan.hasNextInt()) {
m = scan.nextInt();
System.out.println(m);
}
System.out.println("请输入一个小数:");
if (scan.hasNextFloat()) {
n = scan.nextFloat();
System.out.println(n);
}
scan.close();
}
}
运行结果:
请输入一个整数:
36000
36000
请输入一个小数:
3.6
3.6
2.6.3 示例
接收多个输入,并求和
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
// 求和
int a = 0;
System.out.println("请输入一个整数(输入非整数结束程序运行):");
while (scan.hasNextInt()) {
a = a + scan.nextInt();
System.out.println("请继续输入:");
}
System.out.println("总和:" + a);
scan.close();
}
}
运行结果:
请输入一个整数(输入非整数结束程序运行):
1
请继续输入:
2
请继续输入:
3
请继续输入:
4
请继续输入:
a
总和:10
2.6.4 接收文件流
Scanner sc=new Scanner(new File("test.txt"));
import java.io.File;
import java.util.Scanner;
import java.io.FileNotFoundException;
public class ScannerFileTest {
public static void main(String[] args) throws FileNotFoundException {
Scanner scan = new Scanner(new File("F:\\JavaStudy\\Source\\FileTest\\src\\people.txt"));
while (scan.hasNextLine()) {
System.out.println("接收到一个字符串:" + scan.nextLine());
}
}
}
运行结果:
接收到一个字符串:rose
接收到一个字符串:lila
接收到一个字符串:john