一、输入及输出的概念
1.1 什么是 I/O
- 是指程序与外部设备或其他计算机进行交互的操作。
- 几乎所有的程序都具有输入与输出操作。
- 如从键盘上读取数据,从本地或网络_上的文件读取数据或写入数据等。
- 通过输入和输出操作可以从外界接收信息,或者是把信息传递给外界。
- Java把这些输入与输出操作用流来实现,通过统一的接口来表示,从而使程序设计更为简单。
1.2 输入输出(I/0)
- 入还是出事相对于内存
- 把数据读到内存中,称为输入,即 input,进行数据的 read 操作
- 往内存外部设备写数据,称为输出,即 output,进行数据的 write 操作
二、File类
2.1 File 类的相关概念
- File类是java. io包中很重要的一个类;
- File类的对象可以表示文件,还可以表示目录,在程序中一个File类对象可以代表一个文件或目录;
- File对象可以对文件或目录的属性进行操作,如:文件名、最后修改日期、文件大小等;
- File对象无法操作文件的具体数据,即不能直接对文件进行读/写操作。
2.2 File 类的构造方法
File 类的构造方法有四种重载方式,不过通常使用如下方式
File(String pathname) //指定文件(或目录)名和路径创建文件对象
File file = new File("1.txt"); // 在当前目录创建文件对象
File file = new File("Java"); // 在当前目录创建一个目录对象
File f3 = new File("D:\\Java");//指明详细的路径以及目录名,请注意双斜线
2.3 File 类的常用方法
2.4 File 类基本操作使用
import java.io.File;
import java.io.IOException;
/**
* file 可以封装目录。也可以封装文件
* */
public class TesyFile {
public static void main(String[] args) throws IOException {
// 在当前目录创建目录对象
File dir = new File("test");
System.out.println(dir.getAbsolutePath());
// 创建目录,判断是否存在
if (!dir.exists()) {
System.out.println("目录不存在,正在创建中。。。");
dir.mkdir();
} else {
System.out.println("目录已经存在");
}
// 创建文件对象
File file = new File("test/1.txt");
// 创建文件对象
if (!file.exists()) {
System.out.println("文件不存在,正在创建。。。");
file.createNewFile();
} else {
System.out.println("文件已创建");
}
// 删除文件
file.delete();
System.out.println("=========== 遍历所有名字 list() ===================");
// 文件遍历
File dirs = new File("G://");
String[] fileNames = dirs.list();
for (String name:fileNames) {
System.out.println(name);
}
System.out.println("=========== 遍历所有对象 listFiles() ===================");
// 文件遍历 (使用 listFiles 的前提是 目录必须存在)
File[] files = dirs.listFiles();
for (File f:files) {
System.out.println(f.getAbsolutePath());
}
// 文件过滤
System.out.println("=========== 遍历符合条件的名字 list(FilenameFilter) 接口===================");
// 遍历目录下所有文件名字, 打印符合过滤条件的
String[] fileNames2 = dir.list(new MyFileNamesFilter());
for (String names2:fileNames2) {
System.out.println(names2);
}
System.out.println("=========== 遍历符合条件的名字 list(FileFilter) 接口===================");
File[] files2 = dir.listFiles(new MyFileFilter());
for (File f:files2) {
System.out.println(f.getAbsolutePath()); // 打印目录
}
}
}
使用文件过滤
1. filenameFilter 接口
import java.io.File;
import java.io.FilenameFilter;
public class MyFileNamesFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
if (name.endsWith(".java")) { // 返回文件名后缀为 .java 的
return true;
} else
return false;
}
}
2. FileFilter 接口
import java.io.File;
import java.io.FileFilter;
public class MyFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
if (pathname.isDirectory()) { // 只输出目录
return true;
} else
return false;
}
}
三、输入流与输出流
3.1 基本概念
- 流按照数据的传输方向分为:
- 输入流:往内存中读叫输入流
- 输出流:从内存中往外些叫输出流
- 所有输入流都是 InputStream 类或者 Reader 类的子类
- 类名以 inputStream 结尾的类都是 InputStream 的子类
- 类名以 Reader 结尾的类都是 Reader类的子类
- 所有输出流都是 OutputStream 类 或者 Writer类的子类
- 类名以 OutputStrean结尾的类都是 OutputStream的子类
- 类名以 Writer结尾的类都是 Writer 类的子类
四、字节流和字符流
4.1 特点
- 从数据流的编码格式上划分
- 字节流
- 字符流
- InputStream 和 OutputStream的子类都是字节流
- 所以字节流可以读写二进制文件,主要处理音频、图片、歌曲等,处理单元为1个字节
- Reader 和 Writer 的子类都是字符流
- 主要处理字符或字符串,字符流处理单元为 2个字节
- 字节流将读取到的字节数据,去指定的编码表中获取对应的文字
4.2 io流中分类
- 字节流中常用类
- 字节输入流:FileInputStream
- 字节输出流:FileOutputStream
- 字符流中常用类
- 字符输入流 FileReader
- 字符输出流 FileWriter
五、节点流与处理流
5.1 特点
- 根据封装类型不同流又分为
- 节点流
- 处理流
5.2 节点流
如果封装流的是某种特定的数据源,如文件、字符串、字符串数组等,则称为节点流
5.3 处理流
如果封装流的是其它流对象,成为处理流。 处理流提供缓冲功能,提高读写效率
5.4 示例 (读取一个文件) FileReader
- 首先创建一个文件名为 1.txt,然后我们在里面随便加点内容,之后保存
- 然后编写读文件的代码
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class TestFileReader {
public static void main(String[] args) {
// 把外部设备的文件 1.txt 包装成 file 对象
File file = new File( "test/1.txt");
// 由于要做读的操作,并且对文件读,所以使用字符输入流,XXXReader
// FileReader 可以直接封装 File 对象,所以使用 FileReader
FileReader fr = null;
try {
fr = new FileReader(file) ;
// 调用 read 方法,读一个字符
int i = fr.read();
while (i != -1) {
System.out.print((char)i);
i=fr.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
// 关闭
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
可以看到,文件的内容正常读取出来了,但是这样做效率很低,因为我们是一个字符一个字符读取的。
5.5 节点流和处理流中常用的类
5.5.1 节点流中常用类
- 字节输入流FileInputStream
- 字节输出流FileOutputStream
- 字符输入流FileReader
-
5.5.2 处理流中常用类
缓冲字节输出流BufferedOutputStream
- 缓冲字节输入流BufferedInputStream
- 缓冲字符输入流BufferedReader
- 缓冲字符输出流BufferedWriter
注意: 在使用字符缓冲输出流时,一定先flush(),然后再close()。避免数据的丟失。
5.5.3 使用 bufferReader 提高读取效率
import java.io.*;
public class TestFileReader {
public static void main(String[] args) {
// 把外部设备的文件 1.txt 包装成 file 对象
File file = new File("test/1.txt");
// 由于要做读的操作,并且对文件读,所以使用字符输入流,XXXReader
// FileReader 可以直接封装 File 对象,所以使用 FileReader
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(file);
// 使用缓冲流,可以一行一行的读取内容
br = new BufferedReader(fr);
// 一步到位 br = new bufferedReader(new FileReader(file));
// int i = fr.read();
// while (i != -1) {
// System.out.print((char)i);
// i=fr.read();
// }
String line = br.readLine();
while (line != null) {
System.out.println(line);
line = br.readLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} finally {
if (fr != null) {
try {
// 关闭
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5.5.4 使用 BufferedWriter 写数据
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
public class TestBufferWriter {
public static void main(String[] args) {
BufferedWriter bw = null;
File file = new File("test/1.txt");
try {
bw = new BufferedWriter(new FileWriter(file,true)); // true 表示不覆盖
bw.write("\n" + new Date() + " : 插入一条新的数据\n");
bw.flush(); // 刷新,保证缓冲区的内容写进去
bw.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
然后再回到上面的读的代码,运行一下,可以看到数据正常的写进去了
5.5.5 使用 FileOutputStream 写入数据
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
// 文件的写操作
public class TestFileOutputStream {
public static void main(String[] args) throws IOException {
File file = new File("test/1.txt");
if (!file.exists()) {
file.createNewFile();
} else {
System.out.println("文件已存在");
}
FileOutputStream fos = new FileOutputStream(file); // 覆盖
FileOutputStream fos1 = new FileOutputStream(file, true); // 追加内容
String str = "窗前明月光\n疑是地上霜\n举头望明月\n低头思故乡";
if (file.exists()) {
fos1.write(str.getBytes()); // 将字符串转换为字节数组写入
} else {
fos.write(str.getBytes());
}
System.out.println("写入成功");
}
}
5.5.6 使用 FileInputStream 读取文件
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
// 使用 FileInputStream 读取文件
public class TestFileInputStream {
public static void main(String[] args) throws IOException {
File file = new File("test/1.txt");
// 文件的字节输入流
FileInputStream fls = new FileInputStream(file);
byte[] bs = new byte[(int) file.length()];
// 一次性读取文件内容
fls.read(bs);
String str = new String(bs);
System.out.println(str);
}
}
5.5.7 使用 BufferedOutputStream写入文件
public static void main(String[] args) throws Exception {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")) ;
//写数据
bos.write("hello".getBytes());
//释放资源
bos.close();
}
5.5.8 使用 BufferedInputStream读取文件
public static void main(String[] args) {
BufferedInputStream bufferedInput = null;
byte[] buffer = new byte[1024];
try {
//创建BufferedInputStream 对象
bufferedInput = new BufferedInputStream(new FileInputStream(filename));
int bytesRead = 0;
//从文件中按字节读取内容,到文件尾部时read方法将返回-1
while ((bytesRead = bufferedInput.read(buffer)) != -1) {
//将读取的字节转为字符串对象
String chunk = new String(buffer, 0, bytesRead);
System.out.print(chunk);
}
} catch (FileNotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
//关闭 BufferedInputStream
try {
if (bufferedInput != null)
bufferedInput.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
六、字符流与字节流的转换
6.1 转换的概念及应用
- 转换流的由来
- 字符流和字节流之间的桥梁
- 方便了字符流与字节流之间的操作
- 转换流的应用
- 字节流中的数据都是字符时,转成字符流操作更搞笑
6.2 字节流转换成字符流的桥梁
InputStreamReader
InputStreamReader (InputStream in) InputStreamReader (InputStream in, String charsetName)
OutpuStreamWriter
OutputStreamWriter (OutputStream out) OutputStreamWriter (OutputStream out,String charsetName)
注意:
它读入字节,并根据指定的编码方式,将之转换为字符流。
使用的编码方式可能由名称指定,或平台可接受的缺省编码方式。
6.3 转换图解
6.4 demo1
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestInputStreamReader {
public static void main(String[] args) {
// 使用标砖输入流转换为 InputStreamReader
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
String line = br.readLine();
while (!line.equals("exit")) {
System.out.println(">>>:" + line);
line = br.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
6.5 demo2 (FileReader、FileWriter 实现)
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
public class HomeWork {
/**
* 使用 FileReader 拷贝文件
* */
public static void main(String[] args) throws IOException {
File file1 = new File("a.txt");
File file2 = new File("copy"); //拷贝的路径
FileReader fr = null;
FileWriter fw = null;
if (!file1.exists()) {
file1.createNewFile();
} else {
System.out.println(file1.getName()+" 存在啦");
}
if (!file2.exists()) {
file2.mkdir();
} else {
System.out.println("目录已经创建了");
}
// 创建
File file3 = new File("copy/a_copied.txt");
if (!file3.exists()) {
file3.createNewFile();
} else {
System.out.println("文件已经存在");
}
// 先给 file1 写入一些数据
fw = new FileWriter(file1);
fw.flush();
fw.write("春眠不觉晓\n处处闻啼鸟\n夜来风雨声\n花落知多少\n"+new Date());
fw.close();
// 再读取 file1 中的数据
fr = new FileReader(file1);
fw = new FileWriter(file3);
// file1
fw.flush();
int i = fr.read();
while (i != -1) {
System.out.print((char)i);
fw.write((char)i);
i=fr.read();
}
fr.close();
fw.close();
}
}
七、Scanner 类
7.1 Scanner 作为扫描类
- Scanner 类位于 java.util 包中,不在 java.io 包中,不属于 IO 流
- Scanner 是一个工具类,主要目标是简化文本的扫描,最长用来获取控制台的输入
- Scanner 获取控制台输入步骤
- 使用控制台输入创建 Scanner 对象
Scanner in = new Scanner(System.in);
调用 Scanner 中 nextXXX 方法,获取需要的数据类型
next, nextInt, nextDouble ….
因此使用 Scanner 比使用 Reader 简单很多很多
7.2 Scanner 示例
import java.util.Scanner;
public class TestScanner {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("请输入字符串:");
while (true) {
String line = s.nextLine();
if (line.equals("exit")) break;
System.out.println(">>> "+line);
}
}
}
八、IO 编程总结
8.1 IO 流一览表:
- JavaSE 所提供的的所有流都位于 java.io 包内
- 分别继承一下四种抽象流类型
- 字节输入流
- 字节输出流
- 字符输入流:
- 字符输出流
8.2 流操作的基本规律
8.3 文件拷贝练习
import java.io.*;
public class TestCopyFile {
public static void main(String[] args) throws IOException {
File file1 = new File("test/1.txt");
File file2 = new File("test/1_copied.txt");
// 提高效率
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(file1));
bw = new BufferedWriter(new FileWriter(file2));
// 读出源文件
String line = br.readLine();
while (line != null) {
// 存数据
bw.write(line+"\n");
System.out.println(line);
line = br.readLine();
}
bw.flush();
bw.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
br.close();
}
}
}