一、文件
- 传统中的文件:中央红头文件、销售许可书、投标书、毕业论文等
- 计算机中的文件:相关记录或放在一起的数据集合
1、File类
- java.io.File
- 可以用来处理文件目录问题
下面通过一段代码来进一步理解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| import java.io.File; import java.io.FileFilter; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.util.Date;
import javax.swing.JFileChooser;
/** * 演示File类的基本使用及常用方法 * File类并不包含对文件的读写操作 */ public class FileDemo {
public static void main(String[] args) throws IOException { //建议:不要直接使用绝对文件名。如果使用了像c:\\test.java之类的文件名,在Windows上正常运行,但不能在其他平台上运行 //应该使用与当前目录相关的文件名 JFileChooser fileChooser = new JFileChooser(new File(".")); //设置文件对话框打开时的根目录 //让FileChooser可以选择文件夹 fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); fileChooser.setFileFilter(new MyFileFilter()); fileChooser.showOpenDialog(null); //显示出选择文件的对话框(null表示无父窗体) //获得用户选择的文件 建议使用时判断file是否为null,如果为null,表示用户点了取消按钮 File file = fileChooser.getSelectedFile(); //获得用户选择的文件 if(null == file){ System.out.println("用户未选择任何文件,系统强制退出!"); System.exit(0); } System.out.println("文件/文件夹是否存在:" + file.exists()); System.out.println("是否是一个文件:" + file.isFile()); System.out.println("是否是一个文件夹:" + file.isDirectory()); System.out.println("文件/文件夹名称:" + file.getName()); System.out.println("文件/文件夹的绝对路径:" + file.getAbsolutePath()); System.out.println("文件/文件夹的最后修改时间:" + new Date(file.lastModified()).toLocaleString()); System.out.println("文件/文件夹所占空间大小:" + file.length() / 1024 + "KB"); System.out.println("是否可读:" + file.canRead()); System.out.println("是否可写:" + file.canWrite()); System.out.println("是否隐藏:" + file.isHidden()); //列出当前目录下的所有文件/文件夹 if(file.isDirectory()){ System.out.println(file.getAbsolutePath() + "路径下的所有文件及文件夹:"); String[] fileNames = file.list(new DirFilter()); for (int i = 0; i < fileNames.length; i++) { System.out.println(fileNames[i]); } }
} static class MyFileFilter extends javax.swing.filechooser.FileFilter{
@Override public boolean accept(File f) { if(f.getName().endsWith("wav")){ return true; } return false; }
@Override public String getDescription() { // TODO Auto-generated method stub return "*.*, *.wav"; } } //补充:选学 /** * 我们自定义的文件名过滤器类,必须实现FilenameFileter接口 */ static class DirFilter implements FilenameFilter{
@Override public boolean accept(File dir, String name) { //假设我们要求只显示git为后缀的文件,过滤掉其他后缀 if(name.endsWith("wav")){ return true; } return false; } } }
|
2、文件中的数据操作
- 文件中的数据操作
- 在Java中将数据的输入/输出抽象为流(stream)
二、字节流
1、Java中流的分类
- 在Java中的操作文件主要有两大类:字节流、字符流。两类都分为输入和输出操作
- 在字节流中输入数据使用的是InputStream,输出数据主要使用OutputStream
- InputStream和OutputStream是为字节流设计的,主要是用来处理字节或二进制对象
- 在字符流中输入数据主要使用Reader完成,输出数据主要使用Writer完成
- Reader和Writer是为字符流(一个字符占2个字节)设计的,主要用来处理字符或字符串
- 对多国语言支持比较好,如果是音频、视频、图片等建议使用字节流
- 注意:磁盘上保存的文件是二进制字节数据,字符流中多了对编码的处理
2、字节流的架构
- InputStream输入流:
- OutputStream输出流:
- 其他常用的输入流:
4、演示文件输入、输出流的基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Scanner;
/** * 演示文件输入、输出流的基本用法 * 注意:目前的讀寫方式還比較原始,建議在這裡熟悉InputStream/OutputStream的一些重用方法即可 * 後續會有一些高階的類對讀寫方法進行升級和擴展 */ public class FileStreamDemo { private static final String FilePath = "src/com/javabase/ioStream/FileDemo.java"; public static void main(String[] args) throws IOException { // //ReadFile(); writeFile(); } public static void writeFile() throws IOException{ //注意:此文件默认不存在 final String FilePath1 = "src/com/javabase/ioStream/FileDemo1.java"; OutputStream outStream = new FileOutputStream(FilePath1, false);//第二个参数:是否追加写入 String content = "package com.javabase.ioStream;\n"; content += "//本类由代码自动生成\n"; content += "public class FileDemo1{\n"; content += "\tpublic static void main(String[] args){\n"; content += "\t\tSystem.out.println(\"Hello World!\");\n\t}\n}"; outStream.write(content.getBytes());//核心语句:将字符串转换成字节数组,写入到文件中 //写入完毕后一定记得关闭打开的资源 outStream.close(); System.out.println("内容已成功写入到文件中,请检查:"); System.out.println(FilePath1); } public static void ReadFile() throws IOException{ File file = new File(FilePath);//省略判断 InputStream inputStream = new FileInputStream(file); //inputStream.available() 获取输入流可以读取的文件大小(字节) //读取文件的基本操作 - 相对比较固定 byte[] bytes = new byte[20000]; inputStream.read(bytes); // int count = 0; // while((bytes[count] = (byte)inputStream.read()) != -1){ // count++; // } String content = new String(bytes); //将读取出的字节数组转换成字符串,以便打印 System.out.println(content); inputStream.close(); }
}
|
5、BufferedStream
- 带缓冲的流,就是加强版的Stream,直接上代码(引用老九君的例子):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
| import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream;
/** * 使用带缓冲的流增加读写效率 */ public class BufferedStreamDemo { /** * 注意:本文件路径是在老九君的电脑中 * 如果是本地测试,一定记得将文件路径修改成自己电脑中的路径! */ private static final String FilePath1 = "C:/Users/窖头/Videos/Recordings/Java直播之皇帝选妃项目配套录音.mp3"; private static final String FilePath2 = "C:/Users/窖头/Videos/Recordings/已复制文件.mp3"; public static void main(String[] args) throws IOException { //使用缓冲流装饰系统的输入流对象 // BufferedInputStream inStream = new BufferedInputStream(System.in); // byte[] bytes = new byte[200]; // System.out.println("请输入字符串:"); // inStream.read(bytes); // System.out.println("用户输入的字符串是:" + new String(bytes)); long time = CopyFileByBufferedStream(); System.out.println("拷贝用时:" + time + "毫秒"); //小作业:请各位小伙伴自行使用FileInputStream实现文件的复制 //通过复制所用的时间,对比使用缓存的好处 //通过设置不同的缓存大小,体会效率的区别 } /** * 使用缓存流拷贝文件 * @return 拷贝过程的用时(毫秒) */ private static long CopyFileByBufferedStream(){ File file = new File(FilePath1);//要复制的文件对象 if(!file.exists()){ System.out.println("文件不存在,复制失败!"); return 0; } long starTime = System.currentTimeMillis(); InputStream inStream = null; BufferedInputStream bInStream = null; OutputStream outStream = null; BufferedOutputStream bOutStream = null; try { inStream = new FileInputStream(file); bInStream = new BufferedInputStream(inStream); outStream = new FileOutputStream(FilePath2); bOutStream = new BufferedOutputStream(outStream); int i = -1;//读取出的临时变量 while((i = bInStream.read()) != -1){ bOutStream.write(i); //注意:读取一个字节,就写入到了缓存中!需要在最后,将缓存中的内容写入到文件中!. //即,需要清空缓冲区,将缓冲区的内容写到文件中 - flush() } System.out.println("文件复制成功!"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { //bOutStream.flush(); bOutStream.close();//可以直接调用close方法,内部已经帮我们自动调用了flush方法 outStream.close(); bInStream.close(); inStream.close(); } catch (IOException e) { e.printStackTrace(); } } long endTime = System.currentTimeMillis(); return endTime - starTime; } // static final String FilePath1 = "src/com/xuetang9/javabase/chapter13/FileStreamDemo.java"; // static final String FilePath2 = "src/com/xuetang9/javabase/chapter13/BufferTest.txt"; // public static void main(String[] args) { // FileInputStream fInputStream = null; // BufferedInputStream bInputStream = null; // try { // fInputStream = new FileInputStream(FilePath1); // bInputStream = new BufferedInputStream(fInputStream); // byte[] bytes = new byte[bInputStream.available()]; // bInputStream.read(bytes); // System.out.println(new String(bytes)); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } catch (IOException e) { // e.printStackTrace(); // } finally { // try { // bInputStream.close(); // fInputStream.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } // // BufferedOutputStream bOutStream = null; // try { // bOutStream = new BufferedOutputStream(new FileOutputStream(FilePath2), 10240); // bOutStream.write("今天天气很好!".getBytes()); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } catch (IOException e) { // e.printStackTrace(); // } finally { // try { // bOutStream.close(); // } catch (IOException e) { // e.printStackTrace(); // } // } // // // }
}
|
三、装饰器
仅理论框架,后面会出详细的代码讲解
装饰器有一个固定的写法:
1 2 3
| InputStream inputSteam = new FileInputStream(""); //使用带缓存的流对象装饰输入流对象 BufferedInputStream bInStream = new BufferedInputStream(inputSteam);
|
可以扩展出好几种装饰器,用法类似
四、字符流
1、字符流的架构
2、使用字符流读写文件
- 读取文件
- FileReader
- BufferedReader
- 写入文件
- FileWriter
- BufferedWriter
3、固定的读取格式
1 2 3 4 5 6
| BufferedReader bReader = new BufferedReader(new FileReader(FilePath1)); //固定的读取格式: String line = null; while((line = bReader.readLine()) != null){ System.out.println(line); }
|
4、例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException;
/** * 使用字符流对文件进行基本的读写操作 */ public class ReaderAndWriterDemo { private static final String FilePath1 = "src/com/javabase/ioStream/FileDemo1.java"; private static final String FilePath2 = "src/com/javabase/ioStream/FileDemo1.java"; public static void main(String[] args) { try { BufferedReader bReader = new BufferedReader(new FileReader(FilePath1)); //固定的读取格式: String line = null; while((line = bReader.readLine()) != null){ System.out.println(line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //要写入的字符串 String content = "package com.xuetang9.javabase.chapter13;\n"; content += "//本类由代码自动生成1111111111\n"; content += "public class FileDemo1{\n"; content += "\tpublic static void main(String[] args){\n"; content += "\t\tSystem.out.println(\"Hello World!\");\n\t}\n}"; try(BufferedWriter bWriter = new BufferedWriter(new FileWriter(FilePath2))) { //使用了jdk7以后新增的自动关闭资源的写法 //使用前提:资源类必须实现Closeable接口 bWriter.write(content); //将字符串写入到缓冲中 } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { //注意:由于bWriter.close会抛出IOException,这里的异常就被新结构抑制了 //以下的代码用来查看被抑制的异常信息 if(e.getSuppressed() != null){ Throwable[] throwables = e.getSuppressed(); for(Throwable t : throwables){ System.err.println(t.getMessage() + "cased by " + t.getClass().getSimpleName()); } } }
}
}
|
5、PrintWriter和PrintStream
- printWriter用来处理字符流,一次写入2个字节;PrintStream用来处理*字节流,一次写入1个字节
- 建议:在处理文本文件时,使用PrintWriter
上代码(老九君赞助):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Scanner;
public class PrintWriterDemo { static final String FilePath = "src/com/xuetang9/javabase/chapter13/FileDemo1.java"; public static void main(String[] args) { PrintWriter writer1 = new PrintWriter(System.out); writer1.println("使用PrintWriter打印出的内容!"); writer1.flush(); writer1.close(); // //补充:关于Java中的分隔符 windows - \r\n // String separator = System.getProperty("line.separator");//获得系统默认的分隔符 - 固定写法 // String content = "package com.xuetang9.javabase.chapter13;" + separator; // content += "public class FileDemo1{" + separator; // content += "\tpublic static void main(String[] args){" + separator; // content += "\t\tSystem.out.println(\"HelloWorld!\");" + separator; // content += "\t}" + separator; // content += "}"; // // // // try(PrintWriter writer = new PrintWriter(new File(FilePath))){ // writer.write(content); // System.out.println("写入成功!"); // } catch (FileNotFoundException e) { // e.printStackTrace(); // } // // try(Scanner input = new Scanner(new File(FilePath))){ // StringBuffer value = new StringBuffer(); // while(input.hasNextLine()){ // value.append(input.nextLine()); // value.append(separator); // } // System.out.println("以下是从文件中读取出的内容:"); // System.out.println(value.toString()); // } catch (FileNotFoundException e) { // e.printStackTrace(); // }
}
}
|
五、序列化和反序列化
- 对象的输入和输出
- ObjectInputStream & ObjectOutputStream可以读/写可序列化的对象
- 序列化的作用就是把对象以二进制写入文件(Sava)
- 反序列化的作用时把二进制文件转化为对象(Load)
- 什么情况下需要序列化
- 当想把内存中的对象状态保存到一个文件中或者数据库中的时候
- 当想用套接字在网络上传送对象的时候
- 当想通过RMI(远程方法调用)传输对象时
- 注意:
1、序列化时,只对对象的状态要进行保存,而不管对象的方法
2、当一个父类实现序列化,子类自动实现序列化,不需要显示实现Serializable接口
3、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化
六、随机访问文件
- java.io.RandomAccessFile
- 使用顺序流打开的文件称作顺序访问文件,顺序访问文件的内容不能更新
- RandomAccessFile允许在文件的任意位置上进行读写(随机访问文件)
ps:最后两点没有给出代码的原因。上面给的代码太多了,不方便阅读,如果需要请联系我
Author:
Allen Xue
License:
Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan:
To be or not to be,that is a question.