JAVA----IO
1. File
目前程序运行之后的结果 (程序终止) 数据全部丢失。 都需要==持久化==保存程序运行之后的数据。
磁盘(文件) 内存/缓存(程序不能停)
==代表磁盘里面存在或者不存在的目录/文件== 操作文件/目录的属性。
==1.1 常用构造==
文件和目录路径名的抽象表示
File(String pathname) 文件/目录路径 转换File对象
File(File parent, String child) 指定父级目录+子级文件/目录 转换File对象
File(String parent, String child)
1.2 常用属性
static String pathSeparator 环境变量分割: win: ; unix: :
static char pathSeparatorChar
static String separator 代表系统的盘符分割 win \ unix: /
static char separatorChar D:\\a.txt
==1.3 代表文件==
private static void demo1() {
//1. 创建文件对象
//路径:
//1. 绝对路径 D:\\a.txt http://www.baidu.com
//2. 相对路径 / 根路径 相对于project
// D:\workspace\one\day18\src\a.txt
// day18/src/a.txt
String filePath = "day18/src/a.txt";
File file = new File(filePath);
//System.out.println(file);
System.out.println("文件名称:" + file.getName());
System.out.println("文件绝对路径:" + file.getAbsolutePath());
System.out.println("文件相对路径:" + file.getPath());
System.out.println("文件大小(字节个数):" + file.length());
System.out.println("操作文件最新时间(毫秒数):" + new Date(file.lastModified()));
//判断
System.out.println("判断是否是一个文件:" + file.isFile());
System.out.println("判断文件是否存在:" + file.exists());
//文件权限
//System.out.println("修改文件权限:"+file.setReadOnly());
//System.out.println(file.canRead());
//System.out.println(file.canExecute());
//删除文件
//System.out.println("删除文件:" + file.delete());
}
private static void demo2() {
System.out.println(File.pathSeparator);// ;
System.out.println(File.pathSeparatorChar);
System.out.println(File.separator);// \
System.out.println(File.separatorChar);
File file = new File("day18"+File.separator+"demo1.txt");
System.out.println(file.exists());
//文件不存在 自动创建
try {
if (!file.exists()) {
System.out.println("文件不存在 已经自动创建");
file.createNewFile();
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("创建文件 一定要保证 父级路径是存在的");
}
}
==1.4 代表目录==
private static void demo3() {
//File 代表目录
String path = "day18/src";
// / 相对路径
File directory = new File(path);
System.out.println(directory.getName());
System.out.println(directory.getAbsolutePath());
System.out.println(directory.getPath());
System.out.println(new Date(directory.lastModified()));
//判断
System.out.println(directory.isDirectory());
System.out.println(directory.exists());
}
private static void demo4() {
File dir = new File("day18/demo");
// try {
// if(!dir.exists()){
// dir.createNewFile();
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
//mkdir() vs mkdirs()
//mkdir: 创建1级目录
//mkdirs(): >=1
// System.out.println(dir.mkdirs());
//删除目录: 没有子级资源 (删除空目录)
System.out.println(dir.delete());
}
1.5 查看目录子级
|-com
| |- javasm
| | |-exercise
| | | |- Account.java
| | | |- Account.java
| | | |- Account.java
| | |-file
| | | |- Account.java
|-a.txt
private static void selectChild1(File parentDir, String s) {
if (!parentDir.exists()) {
throw new RuntimeException("父级路径不存在的");
}
File[] files = parentDir.listFiles();
for (File child : files) {
System.out.println(s + child.getName());
if (child.isDirectory()) {
selectChild1(child, "| " + s);
}
}
}
private static void selectChild2(File parent, String s) {
String[] child = parent.list();//获得1级资源名称
//子级是目录的----> File.isDirectory()
for (String name : child) {
System.out.println(s + name);
File childFile = new File(parent, name);
if (childFile.isDirectory()) {
selectChild2(childFile, "| " + s);
}
}
}
1.5 过滤子级资源
private static void selectChild2(File parent, String s) {
String[] child = parent.list();//获得1级资源名称
//子级是目录的----> File.isDirectory()
for (String name : child) {
File childFile = new File(parent, name);
if (childFile.isDirectory()) {//子级目录
System.out.println(s + name);
selectChild2(childFile, "| " + s);
} else {
//只展示文件后缀是java
if (name.endsWith("java")) {
System.out.println(s + name);
}
}
}
}
private static void filterChild(File parent, String s) {
//1级资源
// File[] files = parent.listFiles(new FileFilter() {
// @Override
// public boolean accept(File child) {
// if(child.isDirectory()){
// return true;
// }
// return child.getName().endsWith("java");
// }
// });
File[] files = parent.listFiles(child -> {
if (child.isDirectory()) {
return true;
}
return child.getName().endsWith("java");
});
for (File child : files) {
System.out.println(s + child.getName());
if (child.isDirectory()) {
filterChild(child, "| " + s);
}
}
}
2. IO
File类只能操作属性 无法操作文件里面的数据。 InputStream OutputStream
读: 程序读取文件里面的数据 read
写: 通过程序将数据写入文件中。 write
IO处理设备之间的数据传输。网络 磁盘
从流向进行划分: 输入流 /输出流
从操作内容上进行划分: 字节流 字符流
程序读取文件里面的数据: read 输入流 InputStream
通过程序将数据写入文件中 write 输出流 OutputStream
==2.1 字节流==
计算机里面 所有文件内存存储 都是以字节的形式进行存储。 计算机里面全部都是二进制文件。
万能流。 可以操作计算机里面任意类型的文件。
1. 字节输入流 InputStream
public abstract class InputStream extends Object implements Closeable
是一个物理资源 需要释放 finally
常用方法
abstract int read() 一次读取一个字节内容 -1 返回值: 读取到的字节内容
int read(byte[] b) 一次读取b.length个字节内容 读到的字节内容存储到字节数组里面
返回值: 有效字节个数 -1
int read(byte[] b, int off, int len) 一次读取b.length个字节内容
从off的索引位置 存储len个字节内容到字节数组中 返回值: 有效字节个数 -1
int available() ==> File.length() 获得文件内容大小
常用子类
FileInputStream
FileInputStream(File file)
FileInputStream(String name)
read()
private static void testRead1() {
//读取指定文件数据----> 前提: 文件必须存在
String filePath = "day18/src/a.txt";
InputStream inputStream = null;
try {
//1.创建字节输入流对象--->打开了物理资源
inputStream = new FileInputStream(filePath);
//2. 循环读取文件数据 read
// int read = inputStream.read();
// while (read != -1) {
// System.out.print((char) read);
// read = inputStream.read();
// }
int len;
while ((len = inputStream.read()) != -1) {
System.out.print((char) len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放物理资源
try {
if (inputStream != null) inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try…with…resources
private static void testRead2() {
//jdk1.7+ 提供了一种更加优雅的方式释放资源 (自动释放资源) try...with....resources
try (
//创建流对象 前提: 类 implements Closeable
InputStream inputStream = new FileInputStream("day18/src/a.txt");
) {
//循环读取数据
int len;
while ((len = inputStream.read()) != -1) {
System.out.print((char) len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
read(byte[] by)
private static void testRead3() {
try (
InputStream inputStream = new FileInputStream("day18/src/a.txt")
) {
//读取资源
/* System.out.println(inputStream.available());
byte[] bytes = new byte[inputStream.available()];//length=1024的整数倍
int result = inputStream.read(bytes);//一次读取10个字节 result: 读取的有效的字节个数 -1
//想看数据 操作byte数组 字节数组转String
System.out.println(Arrays.toString(bytes));
//有效字节转String
System.out.println(new String(bytes,0,result));*/
int len;
byte[] bytes = new byte[1024];
while ((len = inputStream.read(bytes)) != -1) {
System.out.print(new String(bytes, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
read(byte[] by, int off,int len)
private static void testRead4() {
try (
InputStream inputStream = new FileInputStream("day18/src/a.txt")
) {
byte[] bytes = new byte[10];
int result = inputStream.read(bytes, 0, bytes.length);
System.out.println(Arrays.toString(bytes));
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
2. 字节输出流OutputStream
public abstract class OutputStream extends Object implements Closeable, Flushable
常用方法
abstract void write(int b)
void write(byte[] b)
void write(byte[] b, int off, int len)
void close()
void flush()
常用子类
FileOutputStream(File file)
FileOutputStream(File file, boolean append)
FileOutputStream(String name)
FileOutputStream(String name, boolean append)
write
public static void main(String[] args) {
//使用输出流: 文件不存在 自动的创建文件==> File.createNewFile()
try (
OutputStream outputStream = new FileOutputStream("day18/src/b.txt",false);
) {
//写入数据
//乱码: 编码格式不一致
outputStream.write("使用输出流".getBytes(Charset.forName("UTF-8")));
outputStream.write('\n');
outputStream.write("使用输出流".getBytes(),0,7);
outputStream.write(97);
outputStream.write('a');
outputStream.write("abc".getBytes());
outputStream.write('\n');
outputStream.write("abcd".getBytes(), 1, 2);
System.out.println("success");
} catch (IOException e) {
e.printStackTrace();
}
}
3. 模拟用户上传头像
文件上传和下载: 将一个地方文件放到另外一个地方 复制/粘贴
public class FileUtil {
private FileUtil() {
}
private static final String TARGET_DIRECTORY = "day18/upload/user/";
// day18/upload/user/2021-05-26/a.jpg
// day18/upload/user/2021-05-27/b.jpg
/**
* 文件上传
*
* @param sourceFilePath 源文件路径
*/
public static String fileUpload(String sourceFilePath) {
Objects.requireNonNull(sourceFilePath);
//读取源文件数据read--->InputStream 写入目标文件里面
//获得当前系统时间
String dateStr = LocalDate.now().toString();
File targetPath = new File(TARGET_DIRECTORY, dateStr);
if (!targetPath.exists()) {
targetPath.mkdirs();
}
//目标文件名称肯定与源文件名称一致
String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);
//保证文件名称唯一性 UUID
fileName = UUID.randomUUID().toString().replace("-", "") + "-" + fileName;
File targetFilePath = new File(targetPath, fileName);
try (
//1.创建流对象
InputStream inputStream = new FileInputStream(sourceFilePath);
OutputStream outputStream = new FileOutputStream(targetFilePath);
) {
//2. 循环读写
//小文件读写
/*int len;
while ((len = inputStream.read()) != -1) {
outputStream.write(len);
}*/
//大文件
//文件总量: 100byte
//读1个 写1个 100次
//byte[] by = new byte[20];
//读20个
//写5次
int len;
byte[] bytes = new byte[1024 * 20];//缓冲
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes,0,len);
}
System.out.println("文件上传成功");
} catch (IOException e) {
e.printStackTrace();
}
return targetFilePath.getPath();
}
public static void main(String[] args) {
// System.out.println(fileUpload("C:\\Users\\DELL\\Pictures\\Saved Pictures\\a.jpg"));
// System.out.println(fileUpload("D:\\a.jpg"));
System.out.println(fileUpload("F:\\tools\\IDE\\idea\\ideaIU-2017.2.4.exe"));
// System.out.println(UUID.randomUUID().toString().replace("-", ""));
}
}
4. 高效字节流
BufferedInputStream: 高效的字节输入流 read
BufferedOutputStream 高效的字节输出流 write
普通的字节输入/输出流 FileInput/OutputStream 文件读写: 效率低的情况
为了提高程序读写的效率 基于装饰者设计模式 装饰了基本 字节输入/输出流的功能 提高了读写的效率。
高效原因: 底层自动提供了缓冲。 byte[] buf = new byte[8192];
BufferedInputStream(InputStream in)
BufferedOutputStream(OutputStream out)
public static String fileUpload(String sourceFilePath) {
Objects.requireNonNull(sourceFilePath);
String dateStr = LocalDate.now().toString();
File targetPath = new File(TARGET_DIRECTORY, dateStr);
if (!targetPath.exists()) {
targetPath.mkdirs();
}
String fileName = sourceFilePath.substring(sourceFilePath.lastIndexOf(File.separator) + 1);
fileName = UUID.randomUUID().toString().replace("-", "") + "-" + fileName;
File targetFilePath = new File(targetPath, fileName);
try (
// InputStream inputStream = new FileInputStream(sourceFilePath);
// OutputStream outputStream = new FileOutputStream(targetFilePath);
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(sourceFilePath));
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(targetFilePath))
) {
byte[] bytes = new byte[1024*7];// <8192
int len;
while ((len = inputStream.read(bytes)) != -1) {
outputStream.write(bytes,0,len);
}
System.out.println("文件上传成功");
} catch (IOException e) {
e.printStackTrace();
}
return targetFilePath.getPath();
}
2.2 字符流
所有的文件全部是二进制的。 操作==文本文件==。 不能操作其它的二进制文件(压缩 视频 图片)
字节流+字符集
一个汉字: 2/3byte
文本文件:
纯文本文本: txt java html
有样式文本文件: doc xls ---->POI
Reader: read 字符输入流
Writer: write 字符输出流
1. 字符输入流 Reader
public abstract class Reader
extends Object
implements Readable, Closeable
常用方法
int read()
int read(char[] cbuf)
abstract int read(char[] cbuf, int off, int len)
常用子类
FileReader
FileReader(File file)
FileReader(String fileName)
read()
private static void demo1() {
//操作纯文本数据: txt java
//字符流操作文件内容: 永远也不会乱码
try (
//1.创建字符输入流对象(要求文件必须存在)
Reader reader = new FileReader("day19/src/demo.txt");
) {
//2. 调用read 循环读取文件内容
/* int len;
while ((len = reader.read()) != -1) {
System.out.print((char) len);
}*/
char[] chars = new char[1024 * 5];
int len;
while ((len = reader.read(chars)) != -1) {
//输出内容 字符数组转换String
System.out.print(new String(chars,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
2. 字符输出流 Writer
public abstract class Writer
extends Object
implements Appendable, Closeable, Flushable
常用子类
常用方法
void write(int c)
void write(char[] cbuf)
void write(String str)
abstract void flush()
void write(String str, int off, int len)
FileWriter
FileWriter(String fileName)
FileWriter(String fileName, boolean append)
FileWriter(File file, boolean append)
FileWriter(File file)
private static void demo1() {
try (
Writer writer = new FileWriter("day19/src/a.ini");
) {
//将数据存储文件中
writer.write('我');
writer.write(97);
writer.write("\n");
writer.write("abc".toCharArray());
writer.write("IO内容");
System.out.println("success");
} catch (IOException e) {
e.printStackTrace();
}
}
3. 文件复制
public static String fileUpload1(String filePath) {
try (
Reader reader = new FileReader(filePath);
Writer writer = new FileWriter(TARGET_DIRECTORY + "a.jpg");
) {
// int len;
// while ((len = reader.read()) != -1) {
// writer.write(len);
// }
char[] chars = new char[1024 * 5];
int len;
while ((len = reader.read(chars)) != -1) {
writer.write(chars, 0, len);
// writer.write(new String(chars,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
==4. 高效字符流==
装饰了基本字符流读写功能。 底层自带缓冲 8192 char[]
read—> FileReader
BufferedReader(Reader in)
String readLine() 一次读取一行 读到末尾 null
模拟用户注册功能,持久化保存用户信息--->存储文件 id-name-pass-age
@SneakyThrows
private static void userReg() {
Scanner input = new Scanner(System.in);//获得用户在控制台录入的数据 read
String userInfoFilePath = "day19/src/userinfo.txt";
@Cleanup
Writer writer = new FileWriter(userInfoFilePath,true);
String answer;
do {
System.out.println("录入name:");
String name = input.next();
System.out.println("录入pass:");
String pass = input.next();
System.out.println("录入age:");
int age = input.nextInt();
//id-name-pass-age
String userInfo = String.join("-", idIndex + "", name, pass, age + "");
//用户注册的完整信息存储到文件里面 write---> OutPutStream Writer
writer.write(userInfo);
writer.write("\n");
System.out.println("是否继续y/n");
answer = input.next();
idIndex++;
} while ("y".equals(answer));
System.out.println("程序结束");
}
查询用户信息:
@SneakyThrows
private static List<UserInfo> selectAllUserInfo(String filePath) {
//read--->输入流--->字节输入流(字符输入流) InputStream Reader
List<UserInfo> userInfoList = new ArrayList<>(10);
//一次读取一行 BufferedReader
@Cleanup
BufferedReader reader = new BufferedReader(new FileReader(filePath));
//循环读取文件数据
String content;
while ((content = reader.readLine()) != null) {
//处理字符串数据
String[] array = content.split("-");
userInfoList.add(new UserInfo(Integer.parseInt(array[0]), array[1], array[2], Integer.parseInt(array[3])));
}
return userInfoList;
}
2.3 其它流
也是字节流或者是字符流的子类。
1. 数据流
属于字节流。 DataInputStream DataOutPutStream 操作字面量类型(基本+String)的数据。
DataInput/DataOutPut 前提: 必须先写
是否可以直接读取一个整数,或者一个小数?
字符流: readLine() ----> boolean 进行类型的转换
将一个用户完整的(属性)信息,写入文件中?
int id = 10001;//4byte
double dou = 100.123;//
boolean flag = true;
void writeUTF(String s); 网络数据传输(聊天)
String readUTF()
public class DataInputStream
extends FilterInputStream
implements DataInput
public class DataOutputStream
extends FilterOutputStream
implements DataOutput
private static void demo2() {
try (
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("day19/src/userinfo.txt"))
) {
int id = 1001;
double balance = 92736.876;
String name = "admin";
boolean flag = false;
dataOutputStream.writeInt(id);
dataOutputStream.writeDouble(balance);
dataOutputStream.writeUTF(name);
dataOutputStream.writeBoolean(flag);
System.out.println("success");
} catch (IOException e) {
e.printStackTrace();
}
}
private static void demo1() {
try (
DataInputStream dataInput = new DataInputStream(new FileInputStream("day19/src/userinfo.txt"));
) {
int num = dataInput.readInt();//4
System.out.println(num);
double dou = dataInput.readDouble();
System.out.println(dou);
String str = dataInput.readUTF();
System.out.println(str);
boolean flag = dataInput.readBoolean();
System.out.println(flag);
//java.io.EOFException end of file
} catch (IOException e) {
e.printStackTrace();
}
}
==2. 序列化流==
也属于字节流。 对象流。增强了一个功能: 读写对象数据。
很多对象的信息也要进行设备间传输 保存磁盘文件。 必须先写在读
ObjectInputStream DataInput ObjectInput read 反序列化
ObjectOutputStream writeObj 序列化流
解决方式: 实现Serializable
java.io.NotSerializableException: com.javasm.io_1.UserInfo
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.javasm.io_2.ObjectStreamDemo.testWriteObj(ObjectStreamDemo.java:31)
at com.javasm.io_2.ObjectStreamDemo.main(ObjectStreamDemo.java:20)
流里面的class文件版本号和本地的class文件的版本号不一致、
解决方式: 1. 重新序列化 重新反序列化 不推荐
固定版本号id
java.io.InvalidClassException: com.javasm.io_1.UserInfo; local class incompatible: stream classdesc serialVersionUID = 8710310155550266680, local class serialVersionUID = 2985618370129842064
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1963)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1829)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2120)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1646)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
at com.javasm.io_2.ObjectStreamDemo.testReadObj(ObjectStreamDemo.java:36)
at com.javasm.io_2.ObjectStreamDemo.main(ObjectStreamDemo.java:23)
3. 转换流
字符流子类。 字节流和字符流相互转换。
==字节流转字符流 (操作网络数据)==
OutputStreamWriter
字节流转字符流 InputStreamRedear
抓取小说平台上的小说内容:
下载小说章节内容到 本地文件中。
InputStreamReader(InputStream in)
InputStreamReader(InputStream in, Charset cs)
private static void downloadNovel(String novelPath) {
//写入到本地磁盘: day19/novel/a.txt
//读写 字符流---> 高效字符流
//网络数据---> 字节流
// URL---> 统一资源定位符
//将字节输入流对象转换成成字符输入流对象
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(new URL(novelPath).openStream()));//需要字符输入流对象
BufferedWriter writer = new BufferedWriter(new FileWriter("day19/novel/a.txt"))
) {
//循环读写
String line;
while ((line = reader.readLine()) != null) {
if(line.contains("<div class=\"read-content j_readContent\" id=\"\">")){
String novel = reader.readLine();
writer.write(novel.replaceAll("<p>","\n"));
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
字符转字节
private static void demo() {
//读取文件内容 read 在控制台打印输出----> 写到控制台上 write
try (
BufferedReader reader = new BufferedReader(new FileReader("day19/novel/a.txt"));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));//写到控制台上
) {
String line;
while ((line = reader.readLine()) != null) {
writer.write(line);//字符流写转换成字节流写----> 字符流转字节流
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
}
==4. Properties==
Properties是Map<K,V> 集合实现类。 属性集。 属性名称—>属性的值
public class PropUtil {
private PropUtil() {
}
private static final String PATH = "user.properties";
private static Properties properties;
static {
properties = new Properties();
try {
properties.load(PropUtil.class.getClassLoader().getResourceAsStream(PATH));
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getValue(@NonNull String key) {
return properties.getProperty(key, "");
}
}