TA的每日心情 | 开心 2021-12-13 21:45 |
---|
签到天数: 15 天 [LV.4]偶尔看看III
|
java中常用的IO操作基本上可以分为四大部分,分别是:File类操作、RandomAccessFile类操作、字节流操作、字符流操作。只要熟练掌握了本文中所列举的所有例子,基本上对于Java的IO流操作就可以说是掌握了。下面将以JUnit测试用例的方式,用一个个例子的方式列出这四大部分中常用的操作例子。一、File类操作File类操作定义了最基本的、与操作系统的稳健系统相关的操作,可以对文件夹、文件进行一系列的操作。 1、常用的一些用法- //1.两个常量
- @Test public void twoConstant(){
- //输出: "/" ":"
- System.out.println(File.separator);
- System.out.println(File.pathSeparator);
- }
- //2.创建新文件
- @Test public void createFile(){
- File f = new File("hello");
- try{
- f.createNewFile();
- System.out.println("创建了文件:" + f.getAbsolutePath());
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- //3.创建一个文件夹
- @Test public void createFolder(){
- try{
- File file = new File("HelloFolder");
- //当一个目录下既没有该名字对应的目录和文件时,才能建立该文件夹
- if(!file.isDirectory() && !file.isFile()){
- file.mkdir();
- //file.mkdirs(); //如果上级目录不存在,那么一并创建上级目录
- }else{
- System.out.println("已存在该名称的文件或文件夹");
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- //4.删除一个文件
- @Test public void deleteFile(){
- try{
- File file = new File("hello");
- if(file.exists()){
- file.delete();
- }else{
- System.out.println("文件不存在");
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- //5.删除一个文件夹(与删除文件一样)
- @Test public void deleteFolder(){
- try{
- File file = new File("HelloFolder");
- if(file.exists()){
- file.delete();
- }else{
- System.out.println("该文件夹不存在");
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- //6.获取指定目录下所有文件的文件名(包括隐藏文件和文件夹)
- @Test public void getAllFileName(){
- try{
- File folder = new File("."); //当前目录
- String[] fileStrs = folder.list();
- for(String str : fileStrs){
- System.out.print(str + " ");
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- //7.获取指定目录下所有文件的路径
- @Test public void getAllFilePath(){
- try{
- File folder = new File("."); //当前目录
- File[] files = folder.listFiles();
- for(File file : files){
- System.out.println(file.getCanonicalPath());
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 2、打印指定目录下的所有文件(递归调用)- package com.chanshuyi.io;
- /**
- * 列出指定目录的全部内容
- * */
- import java.io.*;
- class ListAllFile{
- public static void main(String[] args) {
- File f = new File(".");
- print(f);
- }
-
- //递归打印
- public static void print(File f){
- if(f != null){
- if(f.isDirectory()){
- File[] fileArray = f.listFiles();
- if(fileArray != null){
- for(int i = 0; i < fileArray.length; i++){
- print(fileArray[i]);
- }
- }
- }else{
- System.out.println(f);
- }
- }
- }
- }
复制代码 二、RandomAccessFile类操作RandomAccessFile类可以对文件进行随机访问,比如可以指定读写指针到某一个字节处,也可以读写指针指定跳过指定字节数。简单地说,RandomAccessFile类提供了许多方法,使得我们可以对文件进行更加细致的读写操作。- //8.随机读写文件类
- @Test public void operateRandom(){
- try{
- //1.跳过两个字节读取文件内容
- //文件内容是:Hello, this is demo File.
- RandomAccessFile randomRW = new RandomAccessFile(new File("demo.txt"), "rw");
- randomRW.skipBytes(2); //跳过两个字节,即跳过了"he"两个英文字符(一个英文字符占用1个字节)
- byte b[] = new byte[100];
- int length = randomRW.read(b);
- System.out.println("总共读取了" + length + "个字节,读取的内容是:" + new String(b));
- //总共读取了23个字节,读取的内容是:llo, this is demo File.
- //2.将读写指针跳回文件头重新读取
- randomRW.seek(0);
- length = randomRW.read(b);
- System.out.println("总共读取了" + length + "个字节,读取的内容是:" + new String(b));
- //总共读取了25个字节,读取的内容是:Hello, this is demo File.
- //3.获取读写指针所在地址
- long pointer = randomRW.getFilePointer();
- System.out.println("文件指针地址:" + pointer); //文件指针地址:25
- randomRW.seek(2);
- pointer = randomRW.getFilePointer();
- System.out.println("文件指针地址:" + pointer);//文件指针地址:2
- randomRW.seek(77);
- pointer = randomRW.getFilePointer();
- System.out.println("文件指针地址:" + pointer);//文件指针地址:77
- randomRW.close();
- }catch(Exception e){
- e.printStackTrace();
- }
复制代码 三、字节流读写FileInputStream / FileOutputStream - 实现了对文件的读写操作ObjectInpuStream / ObjectOutputStream - 实现了对序列化对象的读写操作ByteArrayInputStream / ByteArrayOutputStream - 实现了对字节数组的读写操作PipedInputStream / PipedOutputStream - 实现不同线程之间的通信SequenceInputStream - 实现不同输入流的合并(此对象没有对应的OutputStream类)BufferedInputStream / BufferedOutputStream - 实现读写缓存层1、字节流读取 - byte(表示读取的数据类型是byte或byte[])- //15.字节流读取 - byte
- @Test public void readByte(){
- try{
- File file = new File("hello.txt");
- InputStream fos = new FileInputStream(file);
- byte[] bytes = new byte[fos.available()];
- fos.read(bytes);
- String str = new String(bytes);
- System.out.println("文件内容是:\n" + str);
- fos.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 2、字节流读取(缓存) - byte- //字节流读取(缓存) - byte
- @Test public void writeByteWithBuffere(){
- try{
- File file = new File("hello1.txt");
- OutputStream fos = new FileOutputStream(file);
- BufferedOutputStream out = new BufferedOutputStream(fos);
- out.write("你好\n".getBytes());
- out.write("吃饭了么!".getBytes());
- out.flush();
- fos.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 3、字节流写入 - byte- //17.字节流写入 - byte
- @Test public void writeByte(){
- try{
- File file = new File("hello.txt");
- OutputStream fos = new FileOutputStream(file);
- fos.write("Hello Mac.\n你好,Mac.".getBytes());
- fos.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 4、字节流写入(缓存) - byte- //18.字节流写入(缓存) - byte
- @Test public void writeByteWithBuffer(){
- try{
- File file = new File("hello.txt");
- OutputStream fos = new FileOutputStream(file);
- BufferedOutputStream bos = new BufferedOutputStream(fos);
- bos.write("Hello Mac.\n你好,Mac.".getBytes());
- bos.close();
- fos.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 如果你仔细敲过上面4个例子的代码你会发现,其实好像字节流的读取和写入,好像加了缓存和没加缓存,它们的代码好像都差不多啊,至少再写入数据的时候是一样的。而字符流的读取在加了缓存层之后,至少还能直接读取整行数据,字符流的写入加了缓存之后,可以写入换行符。那字节流的缓存究竟有什么必要性呢?确实,从代码以及其方法上看,其实他们并没有什么区别,但是从官方的API文档来看,缓存最重要的一个地方就是减少程序对于磁盘的IO次数。加了缓存的程序再读取的时候会一次性读取很多个字节,之后提供给程序使用,但如果你不加缓存,那么程序就只会读取代码中指定的字节数。这在你一个字节一个字节从文件中读取数据的时候,其差别就凸现出来了。如果你没有使用缓存进行数据读取,那么你每读一个字节的数据,程序就去磁盘读取一次文件,这样会造成磁盘的频繁IO读取,减少磁盘的寿命。5、ObjectInputStream / ObjectOutputStream - 序列化一个对象要被序列化的POJO对象:- package com.chanshuyi.io.po;
- import java.io.Serializable;
- public class Student implements Serializable{
- /**
- * 序列化ID
- */
- private static final long serialVersionUID = 7288449352920655248L;
- private String name;
- private int age;
- private String phone;
- public Student(){
- }
- public Student(String name, int age, String phone){
- this.name = name;
- this.age = age;
- this.phone = phone;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getPhone() {
- return phone;
- }
- public void setPhone(String phone) {
- this.phone = phone;
- }
- public String toString(){
- return name + "," + age + "," + phone;
- }
- }
复制代码 被序列化的POJO对象需要实现Serializable接口。序列化对象方法:- //20.ObjectOutputStream - 序列化对象 - 将对象属性序列化保存
- @Test public void serialized(){
- try{
- Student std = new Student("Tommy", 13, "18923923876");
- ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("StudentObject.obj"));
- oos.writeObject(std);
- oos.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 反序列化对象方法:- //21.ObjectInputStream - 反序列化对象 - 读取序列化后的对象
- @Test public void deSerialized(){
- try{
- ObjectInputStream ois = new ObjectInputStream(new FileInputStream("StudentObject.obj"));
- Student std = (Student)ois.readObject();
- System.out.println(std);
- ois.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 6、ByteArrayInputStream / ByteArrayOutputStream - 操作内存字节数据- //19.ByteArrayInputStream - 内存操作流 - 将内存数据转化为流
- @Test public void random2Stream(){
- try{
- String str = "你好";
- ByteArrayInputStream input = new ByteArrayInputStream(str.getBytes());
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- int temp = 0;
- while((temp = input.read()) != (-1)){
- char ch = (char)temp;
- output.write(Character.toLowerCase(ch));
- }
- String outputStr = output.toString();
- input.close();
- output.close();
- System.out.println(outputStr);
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 7、PipedInputStream / PipedOutputStream - 实现进程间的管道通信接收者:- package com.chanshuyi.io.pineStream;
- import java.io.PipedInputStream;
- /**
- * 管道流 - 接收者
- * @author yurongchan
- *
- */
- public class Receiver implements Runnable{
- private PipedInputStream in = null;
- public Receiver(){
- in = new PipedInputStream();
- }
- public PipedInputStream getIn(){
- return this.in;
- }
- public void run(){
- byte[] b = new byte[1000];
- int length = 0;
- try{
- length = this.in.read(b);
- }catch(Exception e){
- e.printStackTrace();
- }
- System.out.println("接收到的消息:" + new String(b, 0, length));
- }
- }
复制代码 发送者:- package com.chanshuyi.io.pineStream;
- import java.io.PipedOutputStream;
- /**
- * 管道流 - 发送者
- * @author yurongchan
- *
- */
- public class Send implements Runnable{
- private PipedOutputStream out = null;
- public Send(){
- out = new PipedOutputStream();
- }
- public PipedOutputStream getOut(){
- return this.out;
- }
- public void run(){
- String msg = "Hello, I"m outputer.\n你好,我是发送者。";
- try{
- out.write(msg.getBytes());
- out.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
复制代码 测试方法:- //22.PipedInputStream - 在不同线程之间进行通信
- @Test public void pipeContact(){
- try{
- Send send = new Send();
- Receiver receiver = new Receiver();
- try{
- send.getOut().connect(receiver.getIn());
- }catch(Exception e){
- e.printStackTrace();
- }
- new Thread(send).start();
- new Thread(receiver).start();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 8、SequenceInputStream - 合并输入流- //23.SequenceInputStream - 合并几个输入流
- @Test public void sequenceInputStream(){
- try{
- InputStream is1 = new FileInputStream(new File("sequence1.txt"));
- InputStream is2 = new FileInputStream(new File("sequence2.txt"));
- OutputStream os = new FileOutputStream(new File("sequence3.txt"));
- SequenceInputStream sis = new SequenceInputStream(is1, is2);
- int temp = 0;
- while((temp = sis.read()) != -1){
- os.write(temp);
- }
- sis.close();
- is1.close();
- is2.close();
- os.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 之后打开sequence3.txt会发现,1、2文本中的内容都到了sequence3.txt中了。四、字符流读写字符流的读写实际上还是基于字节流实现的,而且数组存储时更多是以字节为单位存储,因此更多时候还是使用字节流进行读写操作。因此对于字符流的读写,我们只需要掌握常用的几个操作即可。InputStreamReader / OutputStreamWriter - 实现字符流的读写BufferedReader / BufferedWriter - 实现字符流的缓存层FileReader / FileWriter - 字符流的工具类1、字符流读取 - char(表示读取的数据类型是char或char[])- //9.字符流读取 - char
- @Test public void writeChar(){
- try{
- InputStreamReader reader = new InputStreamReader(new FileInputStream("OutputStreamWriter.txt"));
- char[] chars = new char[1000];
- int length = reader.read(chars);
- System.out.println("一共读取了" + length + "个字符,内容是:" + new String(chars));
- reader.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 2、字符流读取(缓存) - char- //10.字符流读取(缓存)
- @Test public void writeCharWithBuffer(){
- try{
- InputStreamReader isr = new InputStreamReader(new FileInputStream("BufferedWriter.txt"));
- BufferedReader reader = new BufferedReader(isr);
- String str = "";
- while((str = reader.readLine()) != null && str.length() != 0){
- System.out.println(str);
- }
- reader.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 3、字符流写入 - char / char[] / String- //11.字符流写入
- @Test public void readChar(){
- try{
- OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("OutputStreamWriter.txt"));
- writer.write("AllFileTest.fileReadUtil -> 字符流写入文件");
- writer.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 4、字符流的写入(缓存)- char/ String- //12.字符流写入(缓存)
- @Test public void readCharWithBuffer(){
- try{
- OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("BufferedWriter.txt"));
- BufferedWriter writer = new BufferedWriter(osw);
- writer.write("AllFileTest.fileReadUtil -> 字符流写入文件");
- writer.newLine();//换行
- writer.write("第二行");
- writer.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 总结一下上面四种方式的字符流写入写出,我们会发现两个规律,一个是读写规律,一个是缓存层的规律:· 读写规律。字符流的读取,其读取的数据都是char(字符型)的单个或者数组。而字符流的写入除了可以写入单个或多个char类型的字符歪,还可以直接写入String(字符串)类型。· 缓存层规律。字符流的读写,增加了缓存层之后的一个明显区别就是:加了缓存层(Buffer)之后,字符流读取可以实现整行读取(readLine),而字符流写入可以实现写入换行符(writeLine)。5、文件读取工具类- //13.FileReader - 文件读取工具类(这是加了缓存的。但也可以不加缓存)
- @Test public void fileReadUtil(){
- try{
- FileReader fr = new FileReader(new File("demo.txt"));
- BufferedReader reader = new BufferedReader(fr);
- String str = "";
- while((str = reader.readLine()) != null && str.length() != 0){
- System.out.println(str);
- }
- reader.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 将这个例子与上面的第2个例子,即加了缓存的字符流读取例子相比,你会发现其实这两个例子的区别就只是声明FileReader、InputStreamReader的区别而已。声明FileReader只需要再加上File类型参数即可,而声明InputStreamReader则需要再加上一个FileInputStream类,之后才能跟上File类型的参数。因此,我们才说FileReader是一个文件读取工具类。6、文件写入工具类- //14.FileWriter - 文件写入工具类(这是加了缓存的。但也可以不加缓存)
- @Test public void fileWriteUtil(){
- try{
- FileWriter fw = new FileWriter(new File("FileWriteUtil1.txt"));
- BufferedWriter writer = new BufferedWriter(fw);
- writer.write("HelloMan1");
- writer.newLine();
- writer.write("HelloMan2");
- writer.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 同样的,其实FileWriter与OutputStreamWriter也只是声明上的区别而已。五、其他这里会收集一些不怎么常用,但是有时也会用到的例子,遇到的时候可以快速的查询到。1、追加新的内容- //9.字节流 - 追加新内容
- //无论是字节流还是字符流,要追加新的内容都是再FileOutputStream中指定第二个参数为true
- @Test public void appendFile(){
- try{
- File file = new File("hello.txt");
- OutputStream fos = new FileOutputStream(file, true);
- String str = "\n这是新增加的内容";
- fos.write(str.getBytes());
- fos.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 2、模拟打印流输出数据- //18.打印流 - 模拟打印的方式输出数据
- @Test public void printStream(){
- try{
- PrintStream print = new PrintStream(new FileOutputStream(new File("PrintStream.txt")));
- print.println(true);
- print.println("您好,我是打印输出流");
- print.printf("名字:%s.年龄:%d", "Tom", 32); //格式化输出
- print.close();
- //这里的数据要再PrintStream.txt文件中才能看到
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 3、使用OutputStream向屏幕输出内容- //19.使用OutputStream向屏幕输出内容
- @Test public void systemOutStream(){
- try{
- OutputStream out = System.out;
- out.write("你好".getBytes());
- out.close();
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 4、标准输出重定向- //20.标准输出重定向
- @Test public void redirectOutput(){
- try{
- System.out.println("Print in the Screen. 你好");
- System.setOut(new PrintStream(new FileOutputStream(new File("RedirectOutput.txt"))));
- //下面的输出都将重定向到文件中
- System.out.println("=== 重定向后的输出 ===");
- System.out.println("Hello, Eclipse in Mac.");
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 5、标准输入重定向- //21.标准输入重定向
- @Test public void redirectInput(){
- try{
- File file = new File("RedirectOutput.txt");
- if(!file.exists()){
- System.out.println("文件不存在!");
- return;
- }else{
- System.setIn(new FileInputStream(file));
- byte b[] = new byte[1000];
- int length = System.in.read(b);
- System.out.println("读入的内容为:" + new String(b, 0, length));
- }
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 6、错误输出重定向- //22.错误输出重定向
- @Test public void redirectErrOutput(){
- try{
- System.err.println("Print in the Screen. 你好");
- System.setErr(new PrintStream(new FileOutputStream(new File("RedirectErrOutput.txt"))));
- //下面的输出都将重定向到文件中
- System.err.println("=== 重定向后的错误输出 ===");
- System.err.println("Hello, Eclipse in Mac.");
- }catch(Exception e){
- e.printStackTrace();
- }
- }
复制代码 感谢以下博文的参考:1、http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html2、http://www.cnblogs.com/oubo/archive/2012/01/06/2394638.html |
|