易失存储
持久化存储
存储速度的差异
硬盘的实现
磁盘(利用磁性实现的一种存储方式)
固态硬盘(Soild State Disk SSD)
闪存(Flash Memory)
主要硬盘都是指磁盘
这个文件树只是一个逻辑结构,而不是硬盘上的物理结构
文件的路径
路径的分类
File:它是文件和目录路径名的抽象表示
文件和目录是可以通过File封装成对象的
对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已
。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的。
小贴士:
- 一个File对象代表硬盘中实际存在的一个文件或者目录。
- 无论该路径下是否存在文件或者目录,都不影响File对象的创建。
方法名 | 说明 |
---|---|
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 |
File(String parent, String child) | 从父路径名字符串和子路径名字符串创建新的File实例 |
File(File parent, String child) | 从父抽象路径名和子路径名字符串创建新的File实例 |
public class Demo1 {
public static void main(String[] args) {
//1相对路径字符串
File file = new File("a.txt");
System.out.println(file.getAbsoluteFile());
//2绝对路径字符串
File file1 = new File("C:\\JavaCode\\FileAndIO\\b.txt");
System.out.println(file1.getAbsoluteFile());
//3父路径名字符串+子路径字符串
File file2 = new File("C:\\JavaCode\\FileAndIO", "c.txt");
System.out.println(file2.getAbsoluteFile());
//4父抽象路径名+子路径字符串
File file3 = new File("C:\\JavaCode\\FileAndIO");
File file4 = new File(file3, "d.txt");
System.out.println(file4.getAbsoluteFile());
}
}
C:\JavaCode\FileAndIO\a.txt
C:\JavaCode\FileAndIO\b.txt
C:\JavaCode\FileAndIO\c.txt
C:\JavaCode\FileAndIO\d.txt
\\
比如"E:\\JAVA代码
"在介绍文件操作的方法,先来了解文件数据的组成
对于判断功能,无非就是判断文件的数据信息和元信息
public class Demo2 {
public static void main(String[] args) throws IOException {
File file = new File("test\\a.txt");
//1判断file对象对应的文件是否存在
System.out.println(file.exists()); //输出false
//2对于不存在的文件进行判断是否是文件/文件夹
System.out.println(file.isFile());//输出false
System.out.println(file.isDirectory());//输出false
//3利用file的方法进行创建文件
boolean newFile = file.createNewFile();//输出true
//4对于存在的文件进行判断是否是文件/文件夹
System.out.println(file.isFile());//输出true
System.out.println(file.isDirectory());//输出false
//5对存在的文件进行相关信息的查看
System.out.println(file.getAbsoluteFile());//查看绝对路径
// C:\JavaCode\FileAndIO\test\a.txt
System.out.println(file.getPath());//获得创建file对象时的路径
// test\a.txt
System.out.println(file.getName());//获得文件名带后缀
// a.txt
System.out.println(file.length());//获得文件的内容数据的长度,单位是字节数
// 0
System.out.println(file.lastModified());//返回文件的最后修改时间
}
}
public class Demo3 {
public static void main(String[] args) throws IOException {
//前提条件C:\JavaCode\FileAndIO\test 这个目录存在
File file1 = new File("test\\b.txt");
File file3 = new File("text\\aaa\\c.txt");
//1创建一个新的空的文件 此时路径是一个文件路径
System.out.println(file1.getName()+"父路径是否存在"+new File("test").exists());
System.out.println(file1.getName()+"是否存在"+file1.exists());
System.out.println(file1.createNewFile());
System.out.println(file1.getName()+"是否存在"+file1.exists());
//3创建一个父路径不存在的file对象
System.out.println(file3.getName()+"父路径是否存在"+new File("test\\aaa").exists());
System.out.println(file3.getName()+"是否存在"+file3.exists());
System.out.println(file3.createNewFile());
System.out.println(file3.getName()+"是否存在"+file3.exists());
}
}
b.txt父路径是否存在true
b.txt是否存在true
false
b.txt是否存在true
c.txt父路径是否存在false
c.txt是否存在false
Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
at java.base/java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.base/java.io.File.createNewFile(File.java:1043)
at Demo3.main(Demo3.java:26)
public class Demo3 {
public static void main(String[] args) throws IOException {
//前提条件C:\JavaCode\FileAndIO\test 这个目录存在
//4 mkdir创建一个新的空的文件目录 父路径存在
File file4 = new File("test\\bbb");
System.out.println(file4.getName()+"父路径是否存在"+new File("test").exists());
System.out.println(file4.getName()+"是否存在"+file4.exists());
System.out.println(file4.mkdir());
System.out.println(file4.getName()+"是否存在"+file4.exists());
//5 mkdir创建一个新的空的文件目录 父路径不存在
File file5 = new File("test\\ccc\\ddd");
System.out.println(file5.getName()+"父路径是否存在"+new File("test\\ccc").exists());
System.out.println(file5.getName()+"是否存在"+file5.exists());
System.out.println(file5.mkdir());
System.out.println(file5.getName()+"是否存在"+file5.exists());
}
}
bbb父路径是否存在true
bbb是否存在false
true
bbb是否存在true
ddd父路径是否存在false
ddd是否存在false
false
ddd是否存在false
public class Demo3 {
public static void main(String[] args) throws IOException {
//4 mkdirs创建一个新的空的文件目录 父路径存在
File file5 = new File("test\\bbb");
System.out.println(file5.getName()+"父路径是否存在"+new File("test").exists());
System.out.println(file5.getName()+"是否存在"+file5.exists());
System.out.println(file5.mkdirs());
System.out.println(file5.getName()+"是否存在"+file5.exists());
//5 mkdirs创建一个新的空的文件目录 父路径不存在
File file6 = new File("test\\ccc\\ddd");
System.out.println(file6.getName()+"父路径是否存在"+new File("test\\ccc").exists());
System.out.println(file6.getName()+"是否存在"+file6.exists());
System.out.println(file6.mkdirs());
System.out.println(file6.getName()+"是否存在"+file6.exists());
}
}
bbb父路径是否存在true
bbb是否存在true
false
bbb是否存在true
ddd父路径是否存在false
ddd是否存在false
true
ddd是否存在true
//删除功能
public class Demo4 {
public static void main(String[] args) throws IOException {
File f1 = new File("java1.txt"); //创建在项目文件下
System.out.println(f1.createNewFile());
//删除
System.out.println(f1.delete());
//创建和删除目录
File f2 = new File("itcast");
System.out.println(f2.mkdir());
System.out.println(f2.delete());
System.out.println("----------------------");
//创建cast目录,接着在目录下创建java.txt文件
File f3 = new File("cast");
System.out.println(f3.mkdir());
File f4 = new File("cast\\java.txt");
System.out.println(f4.createNewFile());
System.out.println("----------------------------");
//再次删除:注意得先删除路径下的内容,才能删除文件夹
System.out.println(f3.delete());
System.out.println(f4.delete());
System.out.println(f3.delete());
}
}
true
true
true
true
----------------------
true
true
----------------------------
false
true
true
public String[] list()
:返回一个String数组,表示该File目录中的所有子文件或目录。public File[] listFiles()
:返回一个File数组,表示该File目录中的所有的子文件或目录。public class Demo5 {
public static void main(String[] args) {
File file1 = new File("test");
File[] files = file1.listFiles();
for (File file: files ) {
System.out.println(file.getAbsolutePath());
}
}
}
C:\JavaCode\FileAndIO\test\a.txt
C:\JavaCode\FileAndIO\test\bbb
C:\JavaCode\FileAndIO\test\ccc
小贴士:
调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历。
遍历一个目录下所有文件(包括子目录中的文件)
public class Demo6 {
public static void main(String[] args) {
File file = new File("test");
getAllFilePath(file);
}
public static void getAllFilePath(File file){
//说明当前是个文件夹
File[] files = file.listFiles();
for (File one: files) {
if (one.isDirectory()){
//当前文件是目录
System.out.println(one.getAbsolutePath());
getAllFilePath(one);
}else {
//当前文件是一个文件
System.out.println(one.getAbsolutePath());
}
}
}
}
在当前模块下的aaa文件夹中创建一个a.txt文件
public class Practice1 {
public static void main(String[] args) throws IOException {
//在当前模块下的aaa文件夹中创建一个a.txt文件
File parent = new File("aaa");
//如果没有父路径 则创建 如果有 则不创建
parent.mkdirs();
File file = new File(parent, "a.txt");
boolean newFile = file.createNewFile();
if (newFile){
System.out.println("创建成功");
}else {
System.out.println("创建失败");
}
}
}
找到电脑中所有以avi结尾的电影。(需要考虑子文件夹)
public class Practice1 {
public static void main(String[] args) throws IOException {
//获取该主机下的所有盘符
File[] files = File.listRoots();
for (File file : files) {
findEndWithAVI(file);
}
}
private static void findEndWithAVI(File file){
//获得该目录下所有的文件信息
File[] files = file.listFiles();
for (File one: files) {
//如果是目录,则进目录继续寻找
if(one.isDirectory()){
findEndWithAVI(one);
}else {
//说明当前文件是普通文件 进行判断
if (one.getName().endsWith(".avi")){
System.out.println(one.getAbsolutePath());
}
}
}
}
}
删除多级文件夹
需求: 如果我们要删除一个有内容的文件夹
public class Test4 {
public static void main(String[] args) {
/*
删除一个多级文件夹
如果我们要删除一个有内容的文件夹
1.先删除文件夹里面所有的内容
2.再删除自己
*/
File file = new File("D:\\aaa\\src");
delete(file);
}
/*
* 作用:删除src文件夹
* 参数:要删除的文件夹
* */
public static void delete(File src){
//1.先删除文件夹里面所有的内容
//进入src
File[] files = src.listFiles();
//遍历
for (File file : files) {
//判断,如果是文件,删除
if(file.isFile()){
file.delete();
}else {
//判断,如果是文件夹,就递归
delete(file);
}
}
//2.再删除自己
src.delete();
}
}
需求:统计一个文件夹中每种文件的个数并打印。(考虑子文件夹)
public class Practice1 {
public static void main(String[] args) throws IOException {
// 需求:统计一个文件夹中每种文件的个数并打印。(考虑子文件夹)
// 打印格式如下:
// txt:3个
// doc:4个
// jpg:6个
HashMap<String, Integer> map = new HashMap<>();
File file = new File("test");
map = getCount(file);
}
public static HashMap<String,Integer> getCount(File src){
File[] files = src.listFiles();
HashMap<String, Integer> map = new HashMap<>();
for (File file: files) {
if(file.isFile()){
//说明当前是一个文件 进行统计
String name = file.getName();
String[] arr = name.split("\\.");
if (arr.length>=2){
String endName = arr[arr.length - 1];
if (map.containsKey(endName)){
//说明已经存在这个类型
map.put(endName,map.get(endName)+1);
}else {
//说明还不存在这个类型
map.put(endName,1);
}
}
}else{
//5.判断,如果是文件夹,递归
//sonMap里面是子文件中每一种文件的个数
HashMap<String, Integer> sonMap = getCount(file);
//hm: txt=1 jpg=2 doc=3
//sonMap: txt=3 jpg=1
//遍历sonMap把里面的值累加到hm当中
Set<Map.Entry<String, Integer>> entries = sonMap.entrySet();
for (Map.Entry<String, Integer> entry : entries) {
String key = entry.getKey();
int value = entry.getValue();
if(map.containsKey(key)){
//存在
int count = map.get(key);
count = count + value;
map.put(key,count);
}else{
//不存在
map.put(key,value);
}
}
}
}
return map;
}
生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了ctrl+s
,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。
我们把这种数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input
和输出output
,即流向内存是输入流,流出内存的输出流。
Java中I/O操作主要是指使用java.io
包下的内容,进行输入、输出操作。输入也叫做读取数据,输出也叫做作写出数据。
根据数据的流向分为:输入流和输出流。
其他设备
上读取到内存
中的流。内存
中写出到其他设备
上的流。格局数据的类型分为:字节流和字符流。
这里纯文本文件的区分——如果能够通过Windows自带的记事本打开的文件,能够看懂其中的内容就是纯文本文件
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。在操作流的时候,我们要时刻明确,无论使用什么样的流对象,底层传输的始终为二进制数据。
java.io.OutputStream
抽象类是表示字节输出流的所有类的超类,将指定的字节信息写出到目的地。它定义了字节输出流的基本共性功能方法。
public void close()
:关闭此输出流并释放与此流相关联的任何系统资源。public void flush()
:刷新此输出流并强制任何缓冲的输出字节被写出。public void write(byte[] b)
:将 b.length字节从指定的字节数组写入此输出流。public void write(byte[] b, int off, int len)
:从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。public abstract void write(int b)
:将指定的字节输出流。小贴士:
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
OutputStream
有很多子类,我们从最简单的一个子类开始。
java.io.FileOutputStream
类是文件输出流,用于将数据写出到文件。
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
File file = new File("test\\a.txt");
//1创建输出流对象
FileOutputStream fileOutputStream = new FileOutputStream(file);
//2进行输出操作
fileOutputStream.write(97);
//3资源关闭
fileOutputStream.close();
}
}
public FileOutputStream(File file)
:创建文件输出流以写入由指定的 File对象表示的文件。public FileOutputStream(String name)
: 创建文件输出流以指定的名称写入文件。当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有这个文件,会创建该文件。如果有这个文件,会清空这个文件的数据。
public class WriteDemo {
public static void main(String[] args) throws IOException {
File file = new File("test\\a.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(97);//写入数据为a
byte [] arr = {97,98,99,100};
fileOutputStream.write(arr);//写入数据abcd
fileOutputStream.write(arr,1,2);//写入数据bc
fileOutputStream.close();
}
}
public class WriteDemo {
public static void main(String[] args) throws IOException {
File file = new File("test\\a.txt");
//开启续写模式
FileOutputStream fileOutputStream = new FileOutputStream(file, true);
String str = "abcdefge";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.toString(bytes));//[97, 98, 99, 100, 101, 102, 103, 101]
fileOutputStream.write(bytes);
String str1 = "\r\n";
byte[] bytes1 = str1.getBytes();
fileOutputStream.write(bytes1);//写入换行符
fileOutputStream.write(bytes);
fileOutputStream.close();
}
}
java.io.InputStream
抽象类是表示字节输入流的所有类的超类,可以读取字节信息到内存中。它定义了字节输入流的基本共性功能方法。
public void close()
:关闭此输入流并释放与此流相关联的任何系统资源。public abstract int read()
: 从输入流读取数据的下一个字节。public int read(byte[] b)
: 从输入流中读取一些字节数,并将它们存储到字节数组 b中 。小贴士:
close方法,当完成流的操作时,必须调用此方法,释放系统资源。
FileInputStream(File file)
: 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。FileInputStream(String name)
: 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。当你创建一个流对象时,必须传入一个文件路径。该路径下,如果没有该文件,会抛出FileNotFoundException
。
public class FileInputStreamConstructor throws IOException{
public static void main(String[] args) {
// 使用File对象创建流对象
File file = new File("a.txt");
FileInputStream fos = new FileInputStream(file);
// 使用文件名称创建流对象
FileInputStream fos = new FileInputStream("b.txt");
}
}
read
方法,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回-1
,代码使用演示read(byte[] b)
,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时
,返回-1
,代码使用演示:public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
File file = new File("a.txt");//文件内容是abcdefg
FileInputStream fileInputStream = new FileInputStream(file);
int b;
while ((b=fileInputStream.read())!=-1){
//fileInputStream.read()每次读取一个字节的数据,读取到末尾返回-1
System.out.print((char) b);
}
fileInputStream.close();
}
}
小贴士:
- 虽然读取了一个字节,但是会自动提升为int类型。
- 流操作完毕后,必须释放系统资源,调用close方法,千万记得。
public class FISRead {
public static void main(String[] args) throws IOException{
// 使用文件名称创建流对象.
FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
// 定义变量,作为有效个数
int len ;
// 定义字节数组,作为装字节数据的容器
byte[] b = new byte[2];
// 循环读取
while (( len= fis.read(b))!=-1) {
// 每次读取后,把数组变成字符串打印
System.out.println(new String(b));
}
// 关闭资源
fis.close();
}
}
输出结果:
ab
cd
ed
public class JDPCopy {
public static void main(String[] args) throws IOException {
File oldFile = new File("R-C.jpg");
File newFile = new File("new.jpg");
FileInputStream fileInputStream = new FileInputStream(oldFile);
FileOutputStream fileOutputStream = new FileOutputStream(newFile);
byte[] bytes = new byte[1024];
int len;
while ((len=fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
fileInputStream.close();
fileOutputStream.close();
}
}
小贴士:
流的关闭原则:先开后关,后开先关。
public class ExceptionHandle {
public static void main(String[] args) {
File file = new File("a.txt");
//1普通写法
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//2 jdk7语法糖写法
try (FileInputStream fileInputStream = new FileInputStream(file)){
}catch (IOException e) {
e.printStackTrace();
}
//3 jdk9语法糖写法
FileInputStream fileInputStream1 = new FileInputStream(file);
try (fileInputStream1){
}catch (IOException e) {
e.printStackTrace();
}
}
}
当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
java.io.Reader
抽象类是表示用于读取字符流的所有类的超类,可以读取字符信息到内存中。它定义了字符输入流的基本共性功能方法。
public void close()
:关闭此流并释放与此流相关联的任何系统资源。public int read()
: 从输入流读取一个字符。public int read(char[] cbuf)
: 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。java.io.FileReader
类是读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
小贴士:
字符编码:字节与字符的对应规则。Windows系统的中文编码默认是GBK编码表。idea中UTF-8
字节缓冲区:一个字节数组,用来临时存储字节数据。
public class FileReaderConstructor throws IOException{
public static void main(String[] args) {
// 使用File对象创建流对象
File file = new File("a.txt");
FileReader fr = new FileReader(file);
// 使用文件名称创建流对象
FileReader fr = new FileReader("b.txt");
}
}
public class CharStreamDemo {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("a.txt");
int ch;
//read()默认也是一个一个字节进行读取,如果遇到中文就会一次读取多个
//在读取之后,会进行解码,将二进制的字节解码为对应的码点,也就是二进制
//这个整数也就是字符集上对应的数字
//英文: 文件乱码二进制数据 0110 0001
// read方法进行读取,解码为十进制的97
//中文: 文件里面的二进制数据 11100110 10110001 10001001
// read方法进行读取,解码为十进制的27721
while ((ch=fileReader.read())!=-1){
System.out.println((char) ch);
}
fileReader.close();
}
}
public class CharStreamDemo {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("a.txt");
char []arr =new char[2];//一个char是2个字节 代表一个代码单元(Code Unit)
int len;
while ((len=fileReader.read(arr))!=-1){
for (char c: arr) {
System.out.print(c);
}
}
fileReader.close();
}
java.io.Writer
抽象类是表示用于写出字符流的所有类的超类,将指定的字符信息写出到目的地。它定义了字节输出流的基本共性功能方法。
void write(int c)
写入单个字符。void write(char[] cbuf)
写入字符数组。abstract void write(char[] cbuf, int off, int len)
写入字符数组的某一部分,off数组的开始索引,len写的字符个数。void write(String str)
写入字符串。void write(String str, int off, int len)
写入字符串的某一部分,off字符串的开始索引,len写的字符个数。void flush()
刷新该流的缓冲。void close()
关闭此流,但要先刷新它。java.io.FileWriter
类是写出字符到文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
FileWriter(File file)
: 创建一个新的 FileWriter,给定要读取的File对象。FileWriter(String fileName)
: 创建一个新的 FileWriter,给定要读取的文件的名称。
当你创建一个流对象时,必须传入一个文件路径,类似于FileOutputStream。
public class FileWriterConstructor {
public static void main(String[] args) throws IOException {
// 使用File对象创建流对象
File file = new File("a.txt");
FileWriter fw = new FileWriter(file);
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("b.txt");
}
}
public class WriteDemo {
public static void main(String[] args) throws IOException {
FileWriter fileWriter = new FileWriter("b.txt");
FileOutputStream fileOutputStream = new FileOutputStream("a.txt");
//1写入一个整数
fileWriter.write(25105);//25105表示的是"我"的码点 写入一个字母文件中显示 我
fileOutputStream.write(25105);//如果通过字节流写入,则写入的是一个字节 文件中则会乱码
//2写入一个字符串
fileWriter.write("abcd");
fileWriter.write("abcd",0,2);
//3写入一个字符数组
fileWriter.write(new char[]{'你','好','啊'});
fileWriter.write(new char[]{'你','好','啊'},0,2);
fileWriter.close();
}
}
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush
方法了。
flush
:刷新缓冲区,流对象可以继续使用。close
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。代码使用演示:
public class FWWrite {
public static void main(String[] args) throws IOException {
// 使用文件名称创建流对象
FileWriter fw = new FileWriter("fw.txt");
// 写出数据,通过flush
fw.write('刷'); // 写出第1个字符
fw.flush();
fw.write('新'); // 继续写出第2个字符,写出成功
fw.flush();
// 写出数据,通过close
fw.write('关'); // 写出第1个字符
fw.close();
fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
fw.close();
}
}
小贴士:即便是flush方法写出了数据,操作的最后还是要调用close方法,释放系统资源。
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类:
BufferedInputStream
,BufferedOutputStream
BufferedReader
,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。public BufferedOutputStream(OutputStream out)
: 创建一个新的缓冲输出流。// 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
普通字节流
public class BufferedDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try(FileInputStream fileInputStream = new FileInputStream("video\\test.mp4");
FileOutputStream fileOutputStream = new FileOutputStream("video\\test1.mp4")) {
int b;
while ((b=fileInputStream.read())!=-1){
fileOutputStream.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("普通流复制时间:"+(end - start)+" 毫秒");
}
}
缓冲流
public class BufferedDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try( BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("video\\test.mp4"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("video\\test1.mp4"))) {
int b;
while ((b=bufferedInputStream.read())!=-1){
bufferedOutputStream.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("复制时间:"+(end - start)+" 毫秒");
}
}
利用数组更快
public class BufferedDemo {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try( BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("video\\test.mp4"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream("video\\test2.mp4"))) {
int len;
byte[] bytes = new byte[8*1024];
while ((len=bufferedInputStream.read(bytes))!=-1){
bufferedOutputStream.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("复制时间:"+(end - start)+" 毫秒");
}
}
public BufferedReader(Reader in)
:创建一个 新的缓冲输入流。public BufferedWriter(Writer out)
: 创建一个新的缓冲输出流。构造举例,代码如下:
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
public String readLine()
: 读一行文字。public void newLine()
: 写一行行分隔符,由系统属性定义符号。public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("in.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
System.out.print(line);
System.out.println("------");
}
// 释放资源
br.close();
}
}
public class BufferedWriterDemo throws IOException {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
// 写出数据
bw.write("黑马");
// 写出换行
bw.newLine();
bw.write("程序");
bw.newLine();
bw.write("员");
bw.newLine();
// 释放资源
bw.close();
}
}
输出效果:
黑马
程序
员
public class Test1 {
public static void main(String[] args) throws IOException {
//文件夹的拷贝
File src = new File("test");
File dest = new File("demo");
copyDir(src,dest);
}
private static void copyDir(File src, File dest) throws IOException {
dest.mkdirs();
File[] files = src.listFiles();
for (File file : files) {
if (file.isFile()){
//是文件 进行拷贝
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(new File(dest,file.getName()));
byte[] bytes = new byte[1024];
int len;
while ((len=fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
fileInputStream.close();
fileOutputStream.close();
}else{
//是文件夹 进行递归
copyDir(file,new File(dest,file.getName()));
}
}
}
}
public class Test2 {
public static void main(String[] args) throws IOException {
/*
文本文件中有以下的数据:
2-1-9-4-7-8
将文件中的数据进行排序,变成以下的数据:
1-2-4-7-8-9
*/
FileInputStream fileInputStream = new FileInputStream("a.txt");
StringBuilder sb = new StringBuilder();
int b;
while ((b=fileInputStream.read())!=-1){
sb.append((char) b);
}
String s = sb.toString();
System.out.println(s);
String[] split = s.split("-");
FileOutputStream fileOutputStream = new FileOutputStream("a.txt");
List collect = Arrays.stream(split)
.map(str -> Integer.parseInt(str))
.sorted((o1, o2) -> o1 - o2)
.map(integer -> String.valueOf(integer))
.collect(Collectors.toList());
for (int i = 0; i < collect.size(); i++) {
if(i==collect.size()-1){
fileOutputStream.write(collect.get(i).getBytes());
}else {
fileOutputStream.write((collect.get(i)+"-").getBytes());
}
}
fileInputStream.close();
fileOutputStream.close();
}
}
请将文本信息恢复顺序。
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必得裨补阙漏,有所广益。
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
4.将军向宠,性行淑均,晓畅军事,试用之于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐付托不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
案例分析
public class Test3 {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("b.txt"));
ArrayList<String> list = new ArrayList<>();
String line;
while ((line=bufferedReader.readLine())!=null){
list.add(line);
}
Collections.sort(list, (o1, o2) -> o1.charAt(0)-o2.charAt(0));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("b.txt"));
for (String s : list) {
bufferedWriter.write(s);
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
在IDEA中,使用FileReader
读取项目中的文本文件。由于IDEA的设置,都是默认的UTF-8
编码,所以没有任何问题。但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码。
public class Demo {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("gbkfile.txt");
int b;
while ((b= fileReader.read())!=-1){
System.out.print((char) b);
}
fileReader.close();
}
}
输出结果:
����Ϊ��һ�������긲������
�ݻ�л����һ��
�������£�ϷԺ�������廨Ū��
那么如何读取GBK编码的文件呢?
转换流java.io.InputStreamReader
,是Reader的子类,是从字节流到字符流的桥梁。它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集。
InputStreamReader(InputStream in)
: 创建一个使用默认字符集的字符流。InputStreamReader(InputStream in, String charsetName)
: 创建一个指定字符集的字符流。构造举例,代码如下:
InputStreamReader isr = new InputStreamReader(new FileInputStream("in.txt"));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream("in.txt") , "GBK");
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
创建流对象,指定GBK编码
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("gbkfile.txt"), "GBK");
int b;
while ((b=inputStreamReader.read())!=-1){
System.out.print((char) b);
}
inputStreamReader.close();
}
}
转换流java.io.OutputStreamWriter
,是Writer的子类,是从字符流到字节流的桥梁。使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
OutputStreamWriter(OutputStream in)
: 创建一个使用默认字符集的字符流。OutputStreamWriter(OutputStream in, String charsetName)
: 创建一个指定字符集的字符流。构造举例,代码如下:
OutputStreamWriter isr = new OutputStreamWriter(new FileOutputStream("out.txt"));
OutputStreamWriter isr2 = new OutputStreamWriter(new FileOutputStream("out.txt") , "GBK");
public class OutputDemo {
public static void main(String[] args) throws IOException {
// 定义文件路径
String FileName = "E:\\out.txt";
// 创建流对象,默认UTF8编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
// 写出数据
osw.write("你好"); // 保存为6个字节
osw.close();
// 定义文件路径
String FileName2 = "E:\\out2.txt";
// 创建流对象,指定GBK编码
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
// 写出数据
osw2.write("你好");// 保存为4个字节
osw2.close();
}
}
将GBK编码的文本文件,转换为UTF-8编码的文本文件。
public class TransDemo {
public static void main(String[] args) {
// 1.定义文件路径
String srcFile = "file_gbk.txt";
String destFile = "file_utf8.txt";
// 2.创建流对象
// 2.1 转换输入流,指定GBK编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");
// 2.2 转换输出流,默认utf8编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));
// 3.读写数据
// 3.1 定义数组
char[] cbuf = new char[1024];
// 3.2 定义长度
int len;
// 3.3 循环读取
while ((len = isr.read(cbuf))!=-1) {
// 循环写出
osw.write(cbuf,0,len);
}
// 4.释放资源
osw.close();
isr.close();
}
}
对象序列化:就是把对象保存到磁盘中,或者在网络中传输对象
这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息。
字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现序列化和反序列化就要使用对象序列化流和反序列化流:
java.io.ObjectOutputStream
类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
public ObjectOutputStream(OutputStream out)
: 创建一个指定OutputStream的ObjectOutputStream。构造举例,代码如下:
FileOutputStream fileOut = new FileOutputStream("student.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
java.io.Serializable
接口,Serializable
是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException
。transient
关键字修饰。public class Student implements Serializable {
public String name;
public int age;
public transient String address;
public void addressCheck() {
System.out.println("Address check : " + name + " -- " + address);
}
}
2.写出对象方法
public final void writeObject (Object obj)
: 将指定的对象写出。private static void readStduent() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("student.txt"));
Student student = (Student)objectInputStream.readObject();
System.out.println(student);
}
Serialized data is saved
ObjectInputStream类ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。
public ObjectInputStream(InputStream in)
: 创建一个指定InputStream的ObjectInputStream。ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("student.txt"));
如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream
读取对象的方法:
public final Object readObject ()
: 读取一个对象。private static void readStduent() throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("student.txt"));
Student student = (Student)objectInputStream.readObject();
System.out.println(student);
}
Student{name='lsc', age=23, address='null'}
ClassNotFoundException
异常。**另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException
异常。**发生这个异常的原因如下:
Serializable
接口给需要序列化的类,提供了一个序列版本号。serialVersionUID
该版本号的目的在于验证序列化的对象和对应类是否版本匹配。
public class Student implements Serializable {
// 加入序列版本号
private static final long serialVersionUID = 1L;
public String name;
public int age;
public transient String address;
// 添加新的属性 ,重新编译, 可以反序列化,该属性赋为默认值.
public int sex;
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
}
list.txt
文件中。list.txt
,并遍历集合,打印对象信息。public class ObjectListStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Student student = new Student("lsc", 23, "武汉");
Student student1 = new Student("lsc1", 23, "武汉1");
Student student2 = new Student("lsc2", 23, "武汉2");
ArrayList<Student> students = new ArrayList<>();
students.add(student);
students.add(student1);
students.add(student2);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("list.txt"));
objectOutputStream.writeObject(students);
objectOutputStream.close();
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("list.txt"));
// 读取对象,强转为ArrayList类型
ArrayList<Student> list = (ArrayList<Student>)ois.readObject();
for (int i = 0; i < list.size(); i++ ){
Student s = list.get(i);
System.out.println(student);
}
}
}
打印流特点:只负责输出数据,不负责读取数据
例:字节打印流
//字节打印流
public class Demo03 {
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream("ps.txt");
//写数据
//字节输出流有的方法
ps.write(97); //a
//使用特有方法写数据
ps.print(97); //97
ps.println(98);
//释放文件
ps.close();
}
}
//字符打印流
public class Demo04 {
public static void main(String[] args) throws IOException {
// PrintWriter pw = new PrintWriter("pw.txt");
// pw.write("hello");
// pw.write("\r\n");
// pw.flush();
// pw.write("world");
// pw.flush();
// pw.println("hello");
// pw.flush();
// pw.println("world");
// pw.flush();
PrintWriter pw = new PrintWriter(new FileWriter("pw.txt"), true); //true实现自动刷新
pw.println("hello");
pw.println("world");
pw.close();
}
}
System类中有两个静态的成员变量
public class Demo1 {
public static void main(String[] args) throws IOException {
//标准输入流,数据来自键盘输入
InputStream is = System.in;
//字节读数据
int by;
while ((by = is.read()) != -1) {
System.out.println((char) by);
}
//如何把字节流转换为字符流?:转换流
InputStreamReader isr = new InputStreamReader(is);
//使用字符流能不能够实现一次读取一行数据?:这是字符缓冲输入流的特有方法
BufferedReader br = new BufferedReader(isr);
String ch;
while ((ch=br.readLine())!=null){
System.out.println(ch);
}
// //自己实现键盘录入数据太麻烦了,所以java就提供了一个类供我们使用
// Scanner sc = new Scanner(System.in);
}
}
package myOtherStream;
import java.io.PrintStream;
//标准输出流
public class Demo02 {
public static void main(String[] args) {
//public static final PrintStream out:标准输出流
PrintStream ps = System.out;
//能够方便地打印各种数据值
// ps.print("hello");
// ps.print(100);
// ps.println("world");
// ps.println(200);
//System.out的本质是一个字节输出流
System.out.println("hello");
System.out.println(100);
}
}
package myOtherStream;
import java.util.Properties;
import java.util.Set;
//Properties作为Map集合的使用
public class Demo09 {
public static void main(String[] args) {
//创建集合对象
// Properties prop = new Properties();
Properties prop = new Properties();
//存储元素
prop.put("01", "林青霞");
prop.put("02", "张曼玉");
prop.put("03", "王祖贤");
//遍历集合
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
Object value = prop.get(key);
System.out.println(key + "," + value);
}
}
}
package myOtherStream;
import java.util.Properties;
import java.util.Set;
//Properties特有方法
public class Demo10 {
public static void main(String[] args) {
//创建集合对象
Properties prop = new Properties();
prop.setProperty("01", "林青霞"); //接收String类型 ,put是Object类型
prop.setProperty("02", "张曼玉");
prop.setProperty("03", "王祖贤");
//根据键获取值
// System.out.println(prop.getProperty("01"));
// System.out.println(prop.getProperty("04"));
// System.out.println(prop);
//获取键
Set<String> names = prop.stringPropertyNames();
for (String key : names) { //String类型,上个例子是Object类型
// System.out.println(key);
String value = prop.getProperty(key);
System.out.println(key + "," + value);
}
}
}
//集合中的数据保存到文件
public class Demo11 {
public static void main(String[] args) throws IOException {
//把集合在中的数据保存到文件
myStore();
//把文件中的数据加载到集合
myLoad();
}
private static void myLoad() throws IOException {
Properties prop = new Properties();
//load加载
FileReader fr = new FileReader("D:\\itcast\\fw.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("01", "林青霞");
prop.setProperty("02", "张曼玉");
prop.setProperty("03", "王祖贤");
FileWriter fw = new FileWriter("D:\\itcast\\fw.txt");
prop.store(fw, null); //null指的是描述信息
fw.close();
}
}
va
package myOtherStream;
import java.util.Properties;
import java.util.Set;
//Properties特有方法
public class Demo10 {
public static void main(String[] args) {
//创建集合对象
Properties prop = new Properties();
prop.setProperty(“01”, “林青霞”); //接收String类型 ,put是Object类型
prop.setProperty(“02”, “张曼玉”);
prop.setProperty(“03”, “王祖贤”);
//根据键获取值
// System.out.println(prop.getProperty(“01”));
// System.out.println(prop.getProperty(“04”));
// System.out.println(prop);
//获取键
Set names = prop.stringPropertyNames();
for (String key : names) { //String类型,上个例子是Object类型
// System.out.println(key);
String value = prop.getProperty(key);
System.out.println(key + “,” + value);
}
}
}
## Properties和IO流相结合的方法
```java
//集合中的数据保存到文件
public class Demo11 {
public static void main(String[] args) throws IOException {
//把集合在中的数据保存到文件
myStore();
//把文件中的数据加载到集合
myLoad();
}
private static void myLoad() throws IOException {
Properties prop = new Properties();
//load加载
FileReader fr = new FileReader("D:\\itcast\\fw.txt");
prop.load(fr);
fr.close();
System.out.println(prop);
}
private static void myStore() throws IOException {
Properties prop = new Properties();
prop.setProperty("01", "林青霞");
prop.setProperty("02", "张曼玉");
prop.setProperty("03", "王祖贤");
FileWriter fw = new FileWriter("D:\\itcast\\fw.txt");
prop.store(fw, null); //null指的是描述信息
fw.close();
}
}