第三部分Java SE-Java应用
第3单元 Java I/O部分学习笔记
一、什么是I/O流?
- 1.Java的I/O是实现输入和输出的基础,可以方便实现数据的输入和输出操作。
- 2.在Java中把不同的输入/输出源抽象表述为“流”(Stream)。
- 3.通过流的形式允许Java程序使用相同的方式来访问不同的输入/输出源。
- 4.I/O就是Input/Output,即输入/输出,常见的场景:读文件/写文件;上传文件到网络/从网络下载文件;从键盘接收数据/在屏幕上显示信息。
- 5.I/O操作的API位于:java.io包。
二、Java中的I/O分为几类?
面试点
1.按传输方向分为两类:输入流和输出流
- 输入流:读文件、读网络、读键盘(站在CPU的角度)
- 输出流:写文件、写网络、在屏幕输出
2.按读写单位分为两类:字节流和字符流
- 字节流:以字节(byte)为单位读写,父类是InputStream/OutputStream;适用于读二进制文件或文本文件,比如:验证码图片是典型应用。
- 字符流:以字符(char)为单位读写,父类是Reader/Writer;适用于读写文本文件(不带格式),不能直接读写Word、Excel文件,需要使用第三方开源组件读写。
- 有格式的操作:使用POI组件
三、File类的使用
java.io.File 必须导包才能使用
1.TODO 如何创建文件(相对路径)
- 方法:createNewFile() 开发:当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
import java.io.File;
public class CreateFile {
public static void main(String[] args) {
//在相对路径下 创建文件 info.txt
File file1 = new File("src/info.txt");
//使用了转义字符
File file2 = new File("src\\info1.txt");
boolean flag = false;
try {
flag = file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (flag) {
System.out.println("src文件已创建!");
} else {
System.out.println("文件创建失败!");
}
}
}
2.TODO 如何创建文件(绝对路径)
import java.io.File;
public class CreateFileAbsolute {
public static void main(String[] args) {
File file1 = new File("d:/Javalesson10/log.txt");
//File file2 = new File("d:\\Javalesson10\\Java1018\\src\\log.txt");
boolean flag = false;
try {
flag = file1.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
if (flag) {
System.out.println("log.txt文件已经创建!");
} else {
System.out.println("文件创建失败!");
}
}
}
3.TODO 如何创建目录(单级目录与多级目录)
方法:mkdir() :创建单级目录。 mkdirs():创建多级目录。
import java.io.File;
public class CreateFolder {
public static void main(String[] args) {
//在d盘下创建目录,也可以使用相对路径
File dir = new File("d:/赵彪的目录");
//这个方法智能创建单个目录
boolean flag = dir.mkdir();
if (flag) {
System.out.println("目录创建成功!");
} else {
System.out.println("目录创建失败!");
}
//创建多级目录
File folder = new File("d:/赵彪的目录1/software/常用软件");
boolean flag1 = folder.mkdirs();
if (flag1) {
System.out.println("多级目录创建成功!");
} else {
System.out.println("多级目录创建失败!");
}
}
}
4.TODO 如何删除文件和目录
方法:delete(): 删除由此抽象路径名表示的文件或目录。
import java.io.File;
public class DeleteFile {
public static void main(String[] args) {
File dir = new File("d:/赵彪的目录");
boolean flag = dir.delete();
if (flag) {
System.out.println("单级目录删除成功!");
} else {
System.out.println("单级目录删除失败!");
}
File folder = new File("d:/赵彪的目录1/software/常用软件");
//删除最里边的目录
boolean flag1 = folder.delete();
if (flag1) {
System.out.println("多级目录删除成功!");
} else {
System.out.println("多级目录删除失败!");
}
File file = new File("d:/Javalesson10/log.txt");
boolean flag2 = file.delete();
if (flag2) {
System.out.println("文件删除成功!");
} else {
System.out.println("文件删除失败!");
}
}
}
5.TODO 如何判断是目录还是文件
isFile() :测试此抽象路径名表示的文件是否为普通文件。
isDirectory():测试此抽象路径名表示的文件是否为目录。
import java.io.File;
public class FileOrFolder {
public static void main(String[] args) {
File dir = new File("d:/网页模板");//这个目录得存在
File file = new File("d:/Hello.java");//这个文件得存在
if (dir.isDirectory()) {//目录判断
System.out.println("是目录!");
}
if (dir.isFile()) {//文件判断
System.out.println("是文件!");
}
if (file.isDirectory()) {
System.out.println("是目录!");
}
if (file.isFile()) {
System.out.println("是文件!");
}
}
}
6.TODO 如何获取路径、父目录、文件名
getAbsolutePath():返回此抽象路径名的绝对路径名字符串。
getPath():将此抽象路径名转换为路径名字符串。
getName():返回文件或目录的名称。
getParent():返回此父目录,如果此路径名未命名为父目录,则返回null。
import java.io.File;
public class GetNameAndPath {
public static void main(String[] args) {
File file = new File("d:/Javalesson10/china.txt");//绝对路径
System.out.println(file.getAbsolutePath());
System.out.println(file.getPath());
System.out.println(file.getName());
System.out.println(file.getParent());
System.out.println("--------");
File file2 = new File("src/info.txt");//相对路径
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());//src\info.txt
System.out.println(file2.getName());
System.out.println(file2.getParent());
}
}
四、如何使用字节流读取文件
读写文件的步骤:分三步
1.打开流(含文件创建File)
2.读写文件内容
3.关闭流
1.TODO 使用read() 读文件
方法:read() :从该输入流读取一个字节的数据
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ReadByte {
/**
* 读文件:文件里有汉字:一个汉字两个字节,read读的是一个字节,相当于读了汉字的一半,就会乱码。
*/
public void readChinese() {
//1.创建对象,将硬盘文件和内存对象关联
File file = new File("src/info.txt");
//该类用于读文件,按字节读
FileInputStream fis = null;
try {
//2.打开流,用于读文件,该方法抛出异常,需要捕获
fis = new FileInputStream(file);
//返回值是下一个数据字节,如果文件已读完,返回-1
int count = fis.read();
if (count != -1) {
System.out.println("未到文件末尾!");
} else {
System.out.println("到了文件末尾,文件已经读完!");
}
int con = 0;
while ((con = fis.read()) != -1) {
System.out.println("循环按字节读文件:" + (char)con);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fis != null) {
try {//关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 读文件:文件里有字母和数字:注释掉第一个read()就可以读第一字母了
*/
public void readEnglish() {
//1.创建对象,将硬盘文件和内存对象关联
File file = new File("src/english.txt");//要有这个文件
//该类用于读文件,按字节读
FileInputStream fis = null;
try {
//2.打开流,用于读文件,该方法抛出异常,需要捕获
fis = new FileInputStream(file);
//返回值是下一个数据字节,如果文件已读完,返回-1
int count = fis.read();
if (count != -1) {
System.out.println("未到文件末尾!");
} else {
System.out.println("到了文件末尾,文件已经读完!");
}
int con = 0;
while ((con = fis.read()) != -1) {
System.out.println("循环按字节读文件:" + (char)con);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fis != null) {
try {//关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ReadByte readByte = new ReadByte();
readByte.readChinese();
readByte.readEnglish();
}
}
2.TODO 使用read(byte [] b)读文件
方法:read(byte [] b):一次读多个字节,读多少字节按字节数组的长度定
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ReadByteArray {
/**
* 读文件:文件里有汉字
*/
public static void readChinese() {
//1.创建对象,将硬盘文件和内存对象关联
//info.txt文件先创建好并写好内容
File file = new File("src/info.txt");
//此类用于读取文件,按字节读
FileInputStream fis = null;
try {
//2.打开流,用于读文件,该方法抛出异常,需要捕获
fis = new FileInputStream(file);
//定义字节数组,每次读20个字节
byte [] content = new byte [20];//长度换成1024后输出结果有什么变化,一次读1KB
//返回值是下一个数据字节,如果文件已读完,返回-1
int len = 0;//用来存储read(byte[]b)方法的返回值,代表每次读入的字节个数;当因为到达文件末尾而没有字节读入时,返回-1
//按content字节数组长度读取
while ((len = fis.read(content)) != -1) {
//观察输出(1个汉字2个字节,如果只读到了汉字的一半,就输出乱码。)
System.out.println("循环按字节读文件:" + (new String(content,0,len)));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
readChinese();
}
}
3.TODO 使用write写文件
方法:write(int b):将指定的字节写入此文件输出流。
write(byte[]b):将b.length个字节从指定字节数组写入此文件输出流。
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class WriteByte {
public static void main(String[] args) {
File file = new File("src/student.txt");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);//默认是清空文件内容
//fos = new FileOutputStream(file,true);//观察文件内容(文件未部追加)
//fos = new FileOutputStream(file,false);//观察文件内容(清空文件内容)
fos.write(97);//把97写入文件
fos.write(98);//把98写入文件
fos.write(99);//把99写入文件
System.out.println("写入成功!请查看文件内容。");
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
五、如何使用字符流读写文件
- 以字符为单位读写,用的是FileReader/FileWriter,位于java.io包中
1.TODO 读文本文件内容
查API文档java.io包的FileReader和BufferedReader
如何使用字符流读文本文件:一次读一行
import java.io.BufferedReader;//按行读取
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ReadTxt {
public static void main(String[] args) {
File file = new File("src/info.txt");//创建文件对象
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(file);//创建FileReader对象
br = new BufferedReader(fr);//创建BufferedReader对象,它有按行读的方法
String strLine = null;//读到的行字符串
int lineNumber = 0;//行号
//br.readLine();//一次读一行,读到尾部了就是null
while ((strLine = br.readLine()) != null) {
System.out.println("第" + (++lineNumber) + "行:");
System.out.println(strLine);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fr != null) {
try {//关闭流,释放资源以免浪费内存
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (br != null) {
try {//关闭流,释放资源以免浪费内存
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.TODO 向文本文件写内容
写文件有多种方式,查文档java.io包的FileWriter和PrintWriter
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 使用字符流向文本文件中写内容:把字符串写入文件中,类中有两个方法:清空内容和尾部追加
*/
public class WriteTxt {
/**
* 写文本文件:清空已有内容
*/
public static void writeClear() {
File file = new File("src/student.txt");
PrintWriter pw = null;
try {
pw = new PrintWriter(file);
pw.println("大家好!这是程序写进来的。");//清空已有内容,写入新的
} catch (Exception e) {
e.printStackTrace();
}finally {
if (pw != null) {
pw.close();
}
}
}
/**
* 写入文本文件,在内容尾部追加
*/
public static void writeAppend() {
File file = new File("src/student.txt");
PrintWriter out = null;
try {//以下在文件尾部追加,不清空原有内容(第二个参数true是关键)
FileWriter fr = new FileWriter(file,true);
//FileWriter fr = new FileWriter(file,false);
out = new PrintWriter(fr);
out.println("在尾部追加内容。。。。");
} catch (Exception e) {
e.printStackTrace();
}finally {
if (out != null) {
out.close();
}
}
}
public static void main(String[] args) {
//单独执行,观察文件内容变化
writeAppend();
//writeClear();
}
}
3.TODO JDK8 提供的读文件方法
- JDK8 开始,提供了新的文件读写简化方法
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
public class ReadFile {
public static void main(String[] args) throws IOException {
//将文件内容读到List集合里
List<String> lines = Files.readAllLines(Paths.get("src/info.txt"),StandardCharsets.UTF_8);
StringBuilder stringBuilder = new StringBuilder();
for (String line : lines) {
stringBuilder.append(line + "\n");
}
String fromFile = stringBuilder.toString();
System.out.println(fromFile);//输出文件内容
}
}
4.TODO JDK8 提供的写文件方法
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class WriteFile {
public static void main(String[] args) throws IOException {
String content = "学号:201720050235 姓名:赵彪 籍贯:天津";
//清空原有内容
Files.write(Paths.get("src/student.txt"),content.getBytes());
//在文件尾部追加
Files.write(Paths.get("src/student.txt"), content.getBytes(), StandardOpenOption.APPEND);
}
}
六、对象序列化和反序列化(了解)
1.序列化目的:
- 将内存对象包含的属性值保存到硬盘文件,长期保存对象数据。
2.反序列化
- 硬盘文件中存放的数据载入内存对象中。
3.使用场景
- 在网络上传输对象
4.什么样的类对象可以被序列化呢?
-
如果一个类的对象要被序列化的话,这个类要实现一个接口:java.io.Serializable,叫做标志接口(此接口中没有任何方法)。
-
transient:暂态关键字,与对象序列化有关。