0
点赞
收藏
分享

微信扫一扫

JAVA -- IO流

File

  • 内存中的数据不能永久存储,硬盘中的数据可以永久存储
  • 通过文件读/写硬盘中的数据

IO流是什么? 

  1. 可以将数据从本地文件中读取出来
  2. 可以将数据从内存保存到本地

File类是什么? 

  1. 告诉jvm要操作的文件/文件夹在哪?
  2. 对文件/文件夹进行操作,包含创建、删除等

File的方法

File的构造方法

File -- 文件和目录:

  • File对象表示文件或目录
  • File仅仅是一个路径名,可以存在,也可以不存在

构造方法:

  • File(String pathname)
  • File(String parent, String child) -- 构造:parent/child
  • File(File parent, String child) -- parent/child 的另一种重载

String parent = "files";
String child = "data.txt";
File file = new File(parent);
File file1 = new File(parent, child);
File file2 = new File(file, child);

File的创建功能
  • boolean createNewFile() throws IOException
  • boolean mkdir() -- 一级文件夹
  • boolean mkdirs() -- 多级文件夹

createNewFile当parent不存在进会抛异常:

String parent = "files";
String child = "data.txt";
File file1 = new File(parent, child);
boolean result = file1.createNewFile();
System.out.println(result);

JAVA -- IO流_properties

idea中相对路径是相对于项目根目录,与当前java类所在的路径无关

String stParent = "files";
String child = "data.txt";
File parent = new File(stParent);
boolean parentResult = parent.mkdir();
System.out.println(parentResult);
File file1 = new File(parent, child);
boolean result = file1.createNewFile();
System.out.println(result);

JAVA -- IO流_字节流_02

在工程根目录下出现了files文件夹..., 再次运行程序,控制能输出两个false

注意点:

  1. 文件/目录存在时,创建失败,返回false
  2. createNewFile只创建文件,如果父目录不存会抛出异常
delete 
  • 不走回收站
  • 可以删除文件夹或者文件
  • 如果文件夹下有文件,则删除失败

// 如果不选删除文件,删除parent的代码会返回false
System.out.println(file1.delete());
System.out.println(parent.delete());

File的获取和判断方法
  • boolean isDirectory()
  • boolean isFile()
  • boolean exists()
  • getName() -- 返回文件或目录名称
  • getPath()
  • getParent()
  • ...

System.out.println(parent.isDirectory());
System.out.println(parent.isFile());
System.out.println("=================get====================");
System.out.println(parent.getName());
System.out.println(file1.getName());
System.out.println(file1.getAbsolutePath());
System.out.println(file1.getPath());
System.out.println(file1.getParent());

还有很多方法,就不一一测试了...

File的listFile方法

返回目录中的文件和目录的File对象数组.

String stParent = "files";
File parent = new File(stParent);
if (!parent.exists()) {
if (!parent.mkdirs()) {
throw new RuntimeException("parent创建失败");
}
}
for (int i = 0; i < 100; i++) {
File file = new File(parent, i + ".txt");
if(i % 5 == 0)
{
file.mkdirs();
}
else {
file.createNewFile();
}
}
File[] files = parent.listFiles();
for (File file : files) {
if(file.isFile())
{
System.out.println(file.getParent() + " --> 是文件");
} else if (file.isDirectory()) {
System.out.println(file.getParent() + " --> 是文件夹");
}
}
// 删除
for (File file : files) {
file.delete();
}
parent.delete();

还有两个重载函数 

public File[] listFiles(FilenameFilter filter);
public File[] listFiles(FileFilter filter);

FilenameFilter和FileFilter是两个接口,不管哪个接口,方法中的参数都可以唯一确定要过滤的文件。

@FunctionalInterface
public interface FileFilter {
/*
* pathname -- 表示文件本身
*/
boolean accept(File pathname);
}
@FunctionalInterface
public interface FilenameFilter {
/*
* dir - file 所在的目录
* name - file 的名称,带后缀
*/
boolean accept(File dir, String name);
}

使用示例:

// 只要文件...
File[] files = parent.listFiles(f -> f.isFile());

IO的概述

目的:读写文件数据

是谁在读写: 内存

分类:

  • 按流向分JAVA -- IO流_字节流_03
  • 数据类型分JAVA -- IO流_字符流_04

什么是纯文本文件?

用记事本打开文件,并能读懂的文件(.txt)


字节流

字节输出流--写文件(FileOutputStream)

3步曲:

  • 创建输出流对象, 第二个参数 append 表示是否是追加。
  • JAVA -- IO流_字节流_05
  • 写数据JAVA -- IO流_对象流_06
  • 释放资源 fileOutputStream.close();

FileOutputStream fileOutputStream = 
new FileOutputStream("data.txt");
fileOutputStream.write(10);
fileOutputStream.close();

注意事项

  • 文件不存在,会创建
  • 文件存在,默认会清空之前的内容,可以通过第二个参数改变这一行为
  • 一定要释放资源 -- close()

一次写多个数据

public void write(byte b[]) throws IOException;
public void write(byte b[], int off, int len) throws IOException

  • off -- 从哪个位置开始

两个问题 

  • 怎么加换行 -- String.getBytes()把字符串转换成字节数组!
  • 怎么追加 -- 创建流时用第二个参数控制!

FileOutputStream fileOutputStream = 
new FileOutputStream("data.txt");
fileOutputStream
.write("hello world".getBytes(StandardCharsets.UTF_8));
fileOutputStream.write("\r\n".getBytes());
fileOutputStream
.write("你好啊".getBytes(StandardCharsets.UTF_8));
fileOutputStream.close();

字节流-try-width-resource 

按alt + ctrl + t:

JAVA -- IO流_字节流_07

try (FileOutputStream fileOutputStream = 
new FileOutputStream("data.txt")) {
fileOutputStream
.write("hello world"
.getBytes(StandardCharsets.UTF_8));
fileOutputStream.write("\r\n".getBytes());
fileOutputStream
.write("你好啊"
.getBytes(StandardCharsets.UTF_8));
}

字节输入流 -- 读文件(FileInputStream)

三步曲

  • 创建对象 new FileInputStream("data.txt")
  • 读数据 fileInputStream.read()
  • 释放资源 fileInputStream.close()

read一次读取一个字节,返回 -1 到文件尾了:

try (FileInputStream fileInputStream = 
new FileInputStream("data.txt")) {
int read = fileInputStream.read();
System.out.println(read);
}

读多个字节 

try (FileInputStream fileInputStream = 
new FileInputStream("data.txt")) {
byte[] bs = new byte[10];
System.out.println(fileInputStream.read(bs));
String str = new String(bs, StandardCharsets.UTF_8);
System.out.println(str);
}

缓冲流(BufferedOutputStream && BufferedInputStream)

  • BufferedOutputStream -- 字节缓冲输出流

try (FileOutputStream fileOutputStream = 
new FileOutputStream("data.txt")) {
try (BufferedOutputStream bufferedOutputStream =
new BufferedOutputStream(fileOutputStream)) {
bufferedOutputStream
.write("hello world".getBytes(StandardCharsets.UTF_8));
}
}

  • BufferedInputStream -- 字节缓冲输入流

try (FileInputStream fileInputStream = new FileInputStream("data.txt")) {
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) {
int read = bufferedInputStream.read();
while (read != -1) {
System.out.println((char)read);
read = bufferedInputStream.read();
}
}
}

它们只能通过字节流来构造。

字符流&字符缓冲流

中文码问题

字节流操作文本文件出现乱码的问题 

try (BufferedOutputStream bufferedOutputStream = 
new BufferedOutputStream(new FileOutputStream("data.txt"))) {
bufferedOutputStream.write("hello 我来也!".getBytes());
}
try (BufferedInputStream bufferedInputStream =
new BufferedInputStream(new FileInputStream("data.txt"))) {
int ch = bufferedInputStream.read();
while (ch != -1) {
System.out.print((char)ch);
ch = bufferedInputStream.read();
}
System.out.println();
}

JAVA -- IO流_字节流_08

  • 你可能有注意到,只有一层try块了,通过查看代码知道,BufferedXXXStream在关闭时也会关闭对应的字节流。

字符流-编码表 

JAVA -- IO流_字节流_09

  • windows GBK编码表中用两个字节表示一个中文
  • idea默认使用unicode,unicode使用UTF8编解码格式,三个字节表示一个中文

字符流-编码和解码的方法 :

编码:

  • String.getBytes()使用平台默认的字符集编码,默认字符集编码可以通过​​Charset.defaultCharset().name()​​获得。
  • String.getBytes(String charSetName)重载方法,可以指定字符集编码

// 如果标准字符编译中有定义,IDEA会给出优化建议
"hello 我来也!".getBytes(StandardCharsets.UTF_8);
"hello 我来也!".getBytes("GBK");

解码:

  • String(byte[] bytes), 也是用​​Charset.defaultCharset()​​获得编码
  • String(byte[] bytes, String charsetName),通过第二个参数指定编译

对于中国的程序只要记住:中文字符编码表为​​GBK​​,除非特别需要一般都指定为UTF8.

默认字符集编码可以在操作系统中的设置,如果编码在虚拟机内不支持则使用​​ISO-8859-1​​(不支持中文).

字节流读取中文出现乱码的原因 

  • 如果解码和编码过程使用了不同的字符编译格式,得到的字符串很有可能是乱码。
  • 在上之前的代码中,我们每读一个字符就向控制台输出,中文编码需要一个字节以上,如果只输出一个字节,肯定是乱码。

使用字符流操作文件

字符流-读取中文的过程 

  • 字符流 = 字节流 + 编码表 -- 中文的第一个字节一定是负数。
  • 如果是utf8的编译,会先连续读3个字节,然后解码...

字符流-写出数据(FileWriter) 

  • 创建字符输出流
  • 写数据
  • 释放资源

try (FileWriter fileWriter = new FileWriter("text.txt")) {
fileWriter.write("你好啊");
}

  • FileWriter的构造方法和FileOutputStream使用方法一样
  • 没有设置字符集的接口,内部直接使用了默认字符集,JDK11以前如果要指定编码,可以用转换流,后面有介绍
  • JDK11之后,FileWriter增加了可以传编码的构造

FileWrite使用默认编码--源码分析

JAVA -- IO流_字符流_10

  • FileWriter类中只提供了一些构造函数,在构造函数中先构造一个FileOutputStream对象,然后调用父类单参的构造函数,没有指定字符编码JAVA -- IO流_properties_11
  • OutputStreamWriter单参构函数中,实例化了se(StreamEncoder)成员JAVA -- IO流_对象流_12第二个参数给了null,使用默认字符编码JAVA -- IO流_properties_13

flush和close方法

  • flush把数据正真写到文件,flush之后还可以继续写数据
  • close关闭流,关闭之后,不能再写数据

字符流-读取数据(FileReader)

try (FileReader fileReader = new FileReader("text.txt")) {
int read = fileReader.read();
while (read != -1) {
System.out.println((char)read);
read = fileReader.read();
}
}
try (FileReader fileReader = new FileReader("text.txt")) {
char[] buff = new char[1024];
int nread = fileReader.read(buff);
String s = new String(buff, 0,nread);
System.out.println(s);
}

字符缓冲输入流-读取数据(BufferedReader)

try (BufferedReader bufferedReader = new BufferedReader(new FileReader("text.txt"))) {
int ch = bufferedReader.read();
while (ch != -1) {
System.out.println((char)ch);
ch = bufferedReader.read();
}
}

字符缓冲输出流-输出数据(BufferedWriter)

try (BufferedWriter bufferedWriter = 
new BufferedWriter(new FileWriter("text.txt"))) {

bufferedWriter.write("北京时间");

LocalDateTime now = LocalDateTime.now();

bufferedWriter.write(now.format(
DateTimeFormatter
.ofPattern("yyyy年MM月dd日 HH时mm分ss秒")));

bufferedWriter.newLine();
}

缓冲流-特有方法

  • BufferedWriter.newline()
  • BufferedReader.readLine()

转换流&对象操作流&Properties

转换流

  • 字节流 《《---转换流---》》字符流
  • 字节流 ---InputStreamReader---》》字符流
  • 字节流 《《---OutputStreamReader---字符流

JAVA -- IO流_字符流_14

指定编码读写

InputStreamReader ireader = new
InputStreamReader(
new FileInputStream("text.txt"), "gbk");

try (BufferedReader bufferedReader =
new BufferedReader(ireader)) {

String s = bufferedReader.readLine();
System.out.println(s);

}

因为之前是用utf8的编码写入的,用gpk读出来的是乱码:

JAVA -- IO流_字节流_15

对象操作流

可以把对象以字节流的方式写到本地文件,直接打开文件是读不懂的,需要再次用对象操作流读到内存中。

JAVA -- IO流_字符流_16

序列化

User user = new User();
user.setName("张三丰");
user.setPassword("123456");
try (ObjectOutputStream osb = new
ObjectOutputStream(new FileOutputStream("obj.data"))) {
osb.writeObject(user);
}

写的的对象要实现Serializable(标记性接口)接口

public class User implements Serializable {
}

反序列化

try (ObjectInputStream ibs =
new ObjectInputStream(new FileInputStream("obj.data"))) {
User user = (User)ibs.readObject();
System.out.println(user.getName());
System.out.println(user.getPassword());
}

两个注意点

修改了javabean类的属性,读数据会不会出问题?怎么解决?

  • 修改类的属性后,类的serialVersionUID会改变,如果我们的类中没有定义jvm会根据类中的信息自动的计算出序列号,本地件也会保存这个序列号。读取的时对比这两个值是否相等....
  • 解决方案,可以参考ArrayList类的定义

public class User implements Serializable {

private static final long serialVersionUID = 1;
}

如果对象中的某个属性不想序列化该怎么做?

  • 加​​transient​​关键字

 
public class User implements Serializable {

private static final long serialVersionUID = 1;
private transient String password = "";
}

Properties

  • 它就是一个map对象,没有泛型.
  • 有两个与IO相关联的方法
  • 键对基本都是字符串
作为map集合的基本使用

和map的用法一模一样:

Properties prop = new Properties()
prop.put("name", "张三丰");
prop.put("age", "18");
prop.put("like", "太极");
prop.remove("age");
prop.put("like","打太极");
System.out.println(prop);

特有方法
  • object setProperty(String key, String value)
  • String getProperty(String key)
  • Set<String> stringPropertyNames()

Properties prop = new Properties();
prop.setProperty("name", "张三丰"); // 就是put方法
System.out.println(prop.getProperty("name")); // 就是get方法
Set<String> strings = prop.stringPropertyNames();
System.out.println(strings); // 就是keySet()

load / store

Properties prop = new Properties();
prop.setProperty("name", "zhang san feng");
prop.setProperty("age", "18");
FileWriter writer = new FileWriter("prop.properties");
// 第二个参数是注释,如果不需要写null
prop.store(writer, "none");
writer.close();
Properties prop1 = new Properties();
FileReader fileReader = new FileReader("prop.properties");
prop1.load(fileReader);
fileReader.close();
System.out.println(prop1);

注意事项: 

  • properties文件中不能写中文
  • 等号两边不要写空格,末尾也不要写分号

#none
#Thu Sep 15 17:18:24 CST 2022
age=18
name=zhang shan feng


举报

相关推荐

java io流

Java IO流

【java】io流

java -io流

java IO流

0 条评论