为什么要写这篇文章?帮助更多大(xīn)佬(shǒu)学习,理解。
写的很通俗,结合生活实际应该都比较容易理解。
本文主要内容有IO的理论部分,实际用法,原理,面试题,源码。
----------------------------------------------------------------------------------------
IO流概念
IO流:IO流简单来说就是Input和Output流,IO流主要是用来处理设备之间的数据传输,Java对于数据的操作都是通过流实现,而java用于操作流的对象都在IO包中。
按数据内容分:字节流和字符流
按流向分:输入流(硬盘到内存)和输出流(内存到硬盘)

字节流:因为计算机是以二进制的方式进行运算的,所以字节流能处理所有数据
字符流:一开始是没有字符流的

大家可以从源码中看到发布的版本,字符流的原理是读到数据后不直接处理,而是参照码表后获取对应的文字,然后再对文字进行操作,可以理解成 字符流=字节流+码表,如果你想操作文字字符串类型的数据,那毫无疑问,优先考虑字符流没错~

-----------------------------------------------------------------------------------------------------------

IO流字符流的读写

接下来看一下Java提供了哪些技术来用于IO操作

首先提供了抽象类
字节流的两个父类:InputStream,OutputStream
字符流的两个父类:Reader,Writer

因为不断向上抽取,所以功能变得不具体了,很抽象,形成了抽象类。所以要看父类,一看就知道是做什么用的。用子类,子类有很多具体的功能。

大家对文本应该都比较熟悉,所以先来介绍一下Writer的子类FileWriter,这些体系的子类都以父类名作为后缀,前缀就是该对象的功能,比如FileWriter,一看就知道是写文件的便捷类。
FileWriter

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {private static final String LINE_SEPARATOR = System.getProperty("line.separator");//解决不同操作平台写入换行问题
    public static void main(String[] args) throws IOException {FileWriter fileWriter = new FileWriter("abc.txt",true);//创建FileWriter对象,构造函数填写目的地,true代表可以续写,不覆盖
        fileWriter.write("456" + LINE_SEPARATOR + "789");//写到缓存区中一个字符串
        fileWriter.flush();//刷出缓冲区,写到硬盘中
        fileWriter.close();//关闭,关闭前会调用一次flush方法。因为写的功能调用的是windows的系统资源,所以用完了要关了,但关了再写就不能写了

        //想象一下记事本
        //write就像写了后没保存,断电后就没了
        //flush就相当于保存操作,把你写到内存的东西保存到了硬盘
        //close就相当于关闭了记事本,但是关闭时候提示了你保存(关闭前保存)
    }
}

执行完成后,看一下

写完事了,在玩一下读。读的话用的哪个类,猜也能猜的差不多。FileReader

首先是一个字符一个字符读,这个比较简单,就是读到了就返回,都不到就返回-1

public class FileReaderDemo
{public static void main(String[] args) throws IOException {FileReader fileReader = new FileReader("abc.txt");//读这个文件
        int c;//用于接收单个字符
        while((c = fileReader.read()) != -1)//如果当前读到的字符不是-1,就一直读。-1是规定的没读到的标识
        {System.out.print((char)c);//读到后转一下显示
        }}
}

一个一个读不爽?一堆一堆读!

这是我们要读取的文件

这是读的源码

FileReader fileReader = new FileReader("abc.txt");//读这个文件
char[] c = new char[3];
int len;
//一次读满数组,如果读到了,返回读了几个,如果没读到返回-1
while((len = fileReader.read(c)) != -1)
{//输出每次读到的数组转换成字符串
    System.out.print(new String(c,0,len));//new String(char[] c,start,length)重新构造一个字符串,start作为开始索引,length是要获取几个

}

看一下过程,首先我们声明了一个数组c,利用fileReader.read(c)读取。

第一次就把数组读满了,结果为123,返回的是读到的个数,是3

第二次在读的时候,读到了456,也是读满了数组

第三次读的时候,读到了换行符,可以看到在windows下,换行符是\r\n(这不是重点。。)

以此类推还是依此类推?不管了,反正再往下读,就是89J,最后一次读到QK的时候,发现读不满数组了,读到的长度为2,数组的前两个位置被替换变成了QK,最后一个元素由于没有读到被替换,所以还是上回读到的值

最后一次读不到了,返回读到的长度为-1,不进循环,程序结束!

读写都会了后,来个小practice试一试。拷贝D盘的abc.txt到E盘

public class CopyFileDemo {public static void main(String[] args) throws IOException {//拷贝文件的原理就是先读在写
        FileReader fileReader = new FileReader("D:/abc.txt");
        FileWriter fileWriter = new FileWriter("E:/abc.txt");

        char[] c = new char[3];
        int len;
        while((len = fileReader.read(c)) != -1){fileWriter.write(c,0,len);//每次读几个就写几个
        }fileWriter.flush();
        fileWriter.close();
        fileReader.close();
    }
}

--------------------------------------------------------------------------

缓冲区

缓冲区怎么理解呢?就比如你吃瓜子,毛嗑,向日葵,其实是一个东西。你拨一个吃一个肯定不爽,你有空就拨出来,然后放在一个盒子里面,想吃的时候直接拿,就非常海皮。在比如说,你去超市买东西,你推了一个购物车,买一个扔进去一个,到结账的时候,你还得一个一个拿出来,不如在购物车里面加个框,最后把筐给它就完事了(学到没有?)。计算机里面也是,读一次写一次效率肯定不高,可以先读到一个缓冲区里面,然后最后缓冲区装满了,一次性把缓冲区的内容写完,这样效率就得到了提高。缓冲区的出现用于提高流的效率。

BufferedWriter

public static void main(String[] args) throws IOException {FileWriter fileWriter = new FileWriter("abc.txt");
    BufferedWriter bw =  new BufferedWriter(fileWriter);//缓冲区只是作为缓冲对象,真正的写操作还是FileWriter来操作的
    bw.write("123");//写入数据到缓冲区
    bw.flush();//刷到硬盘
    bw.close();//bw关闭,底层关闭的是fileWriter
}

BufferedReader

这个方法有个readLine()方法,可以一次读一行,如果读不到就返回null,你也可以选择一个一个读,也是用read方法,只不过重写了父类的read方法。为什么要重写呢?这就需要分析一下原理了。

public static void main(String[] args) throws IOException {FileReader reader = new FileReader("abc.txt");
    BufferedReader br = new BufferedReader(reader);
    String str = null;
    while((str = br.readLine()) != null){System.out.print(str);
    }
}

BufferedReader中read()方法实现原理

其实就好你去厨房吃馒头,吃一个拿一个肯定不爽嘛,不如拿个筐去,装在筐里面,想吃的时候直接从筐里取就很快。缓冲区也是,先拿到一些到内存中,用的时候直接从内存取就非常快了。如果不重写这个方法,就会调用父类的read,而父类的read并不是从缓冲区里面读的,效率比较低。重写后拿到的数据都是缓冲区里面的数据。
原理就是先获取一批数据放到一个数组里,然后调用一次read方法就从数组里面取一次,取没了就再拿一次放到数组里,取到没有为止。下面的代码是模拟缓冲区read和readLine方法的实现。readLine就是用StringBuffer作为缓冲区,如果读到了换行符就结束方法并返回一行的数据。
public class MyBufferedReader
{FileReader fileReader;
    public MyBufferedReader(FileReader fileReader)构造函数传递需要被缓冲的对象
    {this.fileReader = fileReader;
    }char[] cArr = new char[1024];//缓冲区
    int count;//缓冲区里面元素的数量
    int pos;//用于获取缓冲区的角标

    //自定义read方法
    public int read() throws IOException {//筐里面没有馒头,去厨房取
        if(count == 0) {count = fileReader.read(cArr);//如果缓冲区没有了,就去拿
            pos = 0;//重新获取之后,要把角标重新设置为0
        }//厨房也没有馒头了
        //如果没有数据,拿不到了,返回-1
        if(count < 0){return -1;
        }//在筐里拿馒头吃
        char c = cArr[pos++];//每次自增变量获取
        count--;//缓冲区数量减少
        return c;
    }//自定义readLine方法
    public String readLine() throws IOException {StringBuffer sb = new StringBuffer();
        //判断/r/n
        int c;
        while((c = this.read()) != -1)//循环读
        {if(c == '\r')//如果是/r就跳过去,不追加到字符串中
            {continue;
            }if(c == '\n')//如果是/n,就代表读到了换行符,返回一行的字符串
            {return sb.toString();
            }sb.append(c);//日常追加字符串
        }return sb.toString();
    }
}
-------------------------------------------------------------------------------------
不明白原理也没关系,其实开发中也用不上,但最好了解一下把,不然面试的时候要问呢?

字符流说完了,总结一下把,首先要了解字符流的两个抽象父类,Writer和Reader,下面有一些子类,其中FileReader是读文件用的(输入),常用的方法有int read(),int read(char)。FileWriter是写文件用的(输出),常用的方法有writer(); flush(); close(); 还有给这两位缓冲用的对象,BufferedWriter和BufferedReader,BufferWriter不用多说了,BufferWriter常用的方法有int read();和 String readLine();这两个方法都是重写过的。还有一个LineNumberReader对象没有说,就是读到后加行号,一般用不上,非常简单,自己看下就行了。

-----------------------------------------------------------------------------------------------------

字节流

接下来看字节流,字节流相比字符流就比较万能了,但是对于处理文本来说还是要优先考虑字符流的。可以说字节流能处理任何类型的文件,比如.txt的,jgp的,mp3,mp4,mp5的,mp6有嘛?avi视频文件等等。

InputStream -> FileInputStream,用字节流玩一玩文件,见名知意,写文件用的。

public class FileInputStreamDemo
{public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("abc.txt");
        //一个一个读
        int i;
        while((i = fis.read()) != -1){System.out.print((char)i);
        }//一堆一堆读
        byte[] c = new byte[1024];
        int len;
        while((len = fis.read(c)) != -1){System.out.print(new String(c,0,len));
        }//读小文件用,慎用
        byte[] c2 = new byte[fis.available()];//fis.available文件字节数
        int len2 = fis.read(c2);
        System.out.print(new String(c2,0,len2));
    }
}

和字符流都差不多,只不过接受用的是byte字节,还多了一个fis.available()方法,大批量读不建议使用。

读完事了,来一个写。用到了FileOutputStream

public class FileOutputStreamDemo
{public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("abc.txt");
        fos.write("123456".getBytes());
        fos.flush();//字节流不需要调用flush方法,不需要先写到缓冲区,直接和文件打交道。可以看到继承了父类的flush,并没有重写,
        fos.close();//关闭还是要调用的,子类也进行了重写
    }
}

都是和字符流用法差不多,非常简单。

来一个拷贝mp3的练习,顺便用一下缓冲区,和字符流也差不多,不过多解释。

public class CopyMP3Demo
{public static void main(String[] args) throws IOException {FileInputStream is = new FileInputStream("River flows in you.mp3");
        BufferedInputStream bis = new BufferedInputStream(is);

        FileOutputStream os = new FileOutputStream("abc.mp3");
        BufferedOutputStream bos = new BufferedOutputStream(os);

        byte[] c = new byte[1024];
        int len;
        while((len = bis.read(c)) != -1){bos.write(c,0,len);
            bos.flush();
        }bos.close();
        bis.close();
    }
}

----------------------------------------------------------------------------------------------------------------------------

转换流

需求:让用户输入一段话,按回车结束。如果不是over就输出,是over结束程序。

如果不用转换流,InputStream不存在字符流中的readLine()方法,所以自己写要判断换行符,非常麻烦。这时候就需要将字节流转换成字符流解码

InputStreamReader

InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);//将字节流转换成字符流,放入一个字节流
BufferedReader br = new BufferedReader(isr);//缓冲区高效读取

String line;
while((line = br.readLine()) != null)
{if(line.equals("over"))break;
    System.out.print(line.toString());
}

OutputStreamWriter编码

----------------------------------------------------------------------

学了这么多流对象?到底怎么实战?

1.首先明确源和目的地

源:InputStream Reader

目的地:OutputStream Writer

2.明确数据是否是纯文本

|--是,Reader

|--否,InputStream

目的地:

|--是,Writer

|--否,OutputStream

3.明确具体的设备

源设备:硬盘File,键盘System.in,内存Array,网络Socket

目的地设备:硬盘File,控制台System.out,内存Array,网络Socket

4.是否需要额外功能

高效缓冲区,转换流

-----------------------------------------------------------------------------------------------------------------

明确了这四点之后,来看几个需求

1.复制一个文本文件

首先是纯文本,选择Reader和Writer,具体设备是硬盘,选择FileReader和FileWriter,再看是否需要额外功能,需要缓冲区高效读写,那么选择BufferedReader和BufferedWriter

2.读取键盘录入的数据写到硬盘中

首先也是纯文本,选择Reader和Writer,具体设备是控制台System.in和硬盘File,选择InputStream is = System.in;

和FileWriter,需要额外功能吗?考虑读取到的数据需要转换成字符会更好操作,所以选择转换流,字节转换成字符选用

InputStreamReader,需要高效吗?需要!

那就BufferedReader br = new BufferedReader(new InputStreamReader(System));

BufferedWriter bw = new BufferedWriter(new FileWriter("abc.txt"));

3.将一个文本上的数据显示在控制台上

首先是纯文本,选择Reader和Writer,具体设备是硬盘和控制台,选择FileReader和OutputStream os = System.out;

需要额外功能嘛?需要转换流,OutputStreamWriter(System.out),需要高效嘛?需要!

BufferedReader br = new BufferedReader(new FileReader("abc.txt"));

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

4.将控制台输入的文本,输出在控制台上

纯文本,Reader和Writer,具体设备控制台,选择InputStream is = System.in;和OutputStream os = System.out;

需要额外功能?转换和高效

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

ok,只要明确了对象,使用的话就比较简单了。

---------------------------------------------------------------------------------------------------

到这里,IO的基本对象就学的差不多了

字节流FileInputStream,FileOutputStream,BufferedInputStream,BufferedOutputStream

字符流FileReader,FileWriter,InputStreamReader,OutputStreamWriter,BufferedReader,BufferedWriter

但是这些对象都是操作的数据,操作不了属性。比如获取文件名称,文件大小,操作文件夹等等。

这时候就出现了File类

File类将文件和文件夹封装成了对象,更方便的操作文件和文件夹。没有什么技术含量,就写API的Demo了

//-----------------File构造的几种方式---------------
File f1 = new File("abc.mp3");
File f2 = new File("c:\\","abc.txt");
File f = new File("c:\\");
File f3 = new File(f,"abc.txt");
File f4 = new File("c:" + File.separator + "abc.txt");

//----------------File常用获取------------------
String name = f1.getName();//获取文件名称
String path = f1.getPath();//获取相对路径
String absPath = f1.getAbsolutePath();//获取绝对路径
long len = f1.length();//获取长度
long time = f1.lastModified();//获取最后修改时间

//看上去爽一点的 最后修改时间
Date date = new Date(time);
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
String timeStr = df.format(date);

System.out.println(name);
System.out.println(path);
System.out.println(absPath);
System.out.println(len);
System.out.println(time);
System.out.println(timeStr);

//-----------------------创建与删除--------------------------
//和输出流不同的是,如果没有就创建,有就不做操作

File f5 = new File("abc.txt");
boolean b = f5.createNewFile();//创建一个新的文件

File f6 = new File("abc");
boolean b2 = f6.mkdir();//创建文件夹

File f7 = new File("abc\\def");
boolean b3 = f7.mkdirs();//创建多个文件夹

File f8 = new File("abc\\def");
boolean b4 = f8.delete();//删除,如果文件夹里面有内容,是不可以删除的

f8.deleteOnExit();//在程序退出后删除,比如IO流读取完文件,把文件删除

//----------------------------判断--------------------------------
File f9 = new File("abc.txt");
boolean bb = f9.exists();//判断文件或文件夹之前一定要判断文件是否存在
boolean b5 = f9.isDirectory();
boolean b6 = f9.isFile();

//----------------------------替换---------------------------------
File f10 = new File("123.txt");
f10.renameTo(new File("456.txt"));

//---------------------系统根目录获取容量----------------------------
File[] files = File.listRoots();//获取所有盘符
for(File fx : files)
{System.out.print(fx);
}File fJ = new File("c:\\");
System.out.println(fJ.getFreeSpace());//可用
System.out.println(fJ.getTotalSpace());//总共
System.out.println(fJ.getUsableSpace());//已用

//--------------------------获取目录内容------------------------------------
File fQ = new File("c:\\");
String[] list = fQ.list();
for(String s : list)
{System.out.println(s);
}//--------------------------------过滤目录内容-----------------------------------
//找到所有.java的文件
File fK = new File("c;\\");
fK.list(new FilenameFilter() {@Override
    public boolean accept(File dir, String name) {return name.endsWith(".java");
    }
});

深度遍历文件夹 -- 递归思想

使用递归时,要注意两点

1.结束条件

2.递归次数,小心内存溢出(光压栈不弹栈)

public static void main(String[] args)
{depthDir(new File("d:\\123"),0);
}public static void depthDir(File f,int level)
{System.out.println(printSpace(level) + f.getName());
    level++;
    File[] files = f.listFiles();
    for(int x = 0; x < files.length; x++){//如果当前是文件夹,就在进去遍历
        if(files[x].isDirectory()){depthDir(files[x],level);
        }else
        {System.out.println(printSpace(level)+ files[x].getName());
        }}
}private static String printSpace(int level) {StringBuffer sb = new StringBuffer();
    for(int x = 0; x < level; x++){sb.append("    ");
    }return sb.toString();
}

遍历删除文件夹,Windows下删除文件只能从里往外删

public static void main(String[] args)
{File f = new File("d:\\123");
    deleteDir(f);
}private static void deleteDir(File f) {//遍历,如果不是文件夹就删除,是就继续进去,等到进到最后一个了开始删除
    File[] files = f.listFiles();
    for(int x = 0; x < files.length; x++){if(files[x].isDirectory()){deleteDir(files[x]);
        }else
        {files[x].delete();
        }}f.delete();
}

Java基础之IO流(持续更新中)相关推荐

  1. 【Java基础】· IO流习题详解

    写在前面 Hello大家好, 我是[麟-小白],一位软件工程专业的学生,喜好计算机知识.希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!! ...

  2. 阿里最新面试必备项之Java的String类,持续更新中!

    最新腾讯面试必备项之Java的String类,持续更新中! 1.1 String的特性 String类:代表字符串.Java程序中的所有字符串字面值(如"abc")都作为此类的实例 ...

  3. Java基础学习—— IO流

    Java基础学习-- IO流 1 文件 1.1 文件的创建 1.2 文件常用的方法 2 IO流 2.1 FileInputStream 2.2 FileOutputStream 2.3 文件的拷贝 2 ...

  4. Java基础:IO 流中的 flush

    无意中发现了一个巨牛的人工智能教程,忍不住分享一下给大家.教程不仅是零基础,通俗易懂,而且非常风趣幽默,像看小说一样!觉得太牛了,所以分享给大家.点 这里 可以跳转到教程. 内容概要 Java IO ...

  5. java面试知识迷你版--持续更新中

    **部分知识来源JavaGuide等网络学习资源. java基础 内部类:静态内部类.成员内部类.局部内部类.匿名内部类. 重写(override)要求子类的返回值小于父类(类型相同),修饰符使用范围 ...

  6. Java基础之IO流

    IO流用来处理设备间数据传输,java对数据的操作是通过流的方式,而这些操作流的对象被封装在IO包中.流可以分为字符流和字节流.字符流可以设置编码方式,这就使得处理文本更加方便. IO常用基类 字节流 ...

  7. Java基础知识——IO流

    简介 IO是指Input/Output,即输入和输出.以内存为中心: Input指从外部读入数据到内存,例如,把文件从磁盘读取到内存,从网络读取数据到内存等等 Output指把数据从内存输出到外部,例 ...

  8. 【java基础】IO流是啥?有啥用?(上)

    今天我们说说java代码中对文件的操作,比如新建删除文件,读取文件内容等. File类 File类用于操作文件和目录,可对文件或目录进行新建,删除和重命名等操作.但是如果要访问文件内容本身,就需要用到 ...

  9. Java基础之IO流(一)

    IO流(一) IO流:输入输出的流动 IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的对象都在IO包中 流按操作数据分为两种:字节流与字符流 . 流按流向分为 ...

最新文章

  1. php9宫格抽奖程序_php抽奖算法(适用于九宫格、大转盘)
  2. 学习视觉和语言的多粒度对齐?字节提出新多模态预训练方法 X-VLM:代码已开源!...
  3. scheduledthreadpoolexecutor使用_ScheduledThreadPoolExecutor详解
  4. js 逆向分析的神器 --- v_jstools
  5. 做一个项目,平时都用到哪些工具提高效率(上)[转]
  6. inventor弧度怎么标注_家里房间太大,WiFi信号覆盖不了怎么办?网件新作:分身术...
  7. 区块链:关键阻力的突破会带来持续的积极情绪
  8. 如何进行 JVM 调优
  9. html——页面内跳转
  10. 中文维基百科数据处理
  11. ICE for Linux
  12. excel countifs 计算包含了空白单元格,结果错误,不对,特别大。
  13. android如何实现环形缓冲区
  14. 团队管理之领导力阅读感悟
  15. 清理计算机磁盘碎片,如何清理磁盘碎片
  16. android 微信评论功能,Android仿微信朋友圈点击评论自动定位到相关行功能
  17. 教你在线翻译PDF文档的方法
  18. javax.servlet.ServletException: Could not resolve view with name 'destination/isOtherExist' in servl
  19. 金蝶BOS是什么,能给您带来什么价值?
  20. python量化实战 顾比倒数线_顾比倒数线 主图源码

热门文章

  1. 基于Python/Capl脚本 对通信矩阵报文(Flexray/Can)的周期检测(二)
  2. 编程之美之一摞烙饼的排序1
  3. 老罗的《Android系统源代码情景分析》翻了10遍还看不懂?因为你用错了
  4. CCD CMOS传感器基本工作原理
  5. 远程linux还原本地bak文件,Linux -- 服务器数据备份恢复策略
  6. 解密阿里巴巴加密技术: 爬虫JS逆向实践-1688 【JS混淆加密解析】
  7. 阿里云centos6静默安装oracle11G
  8. 第二证券|钠离子电池将迎来量产 22股净利有望高增长
  9. 新飞飞不显示服务器,《新飞飞》官方网站-新资料片《异域远征军》-网易Q萌战斗网游...
  10. BI Publisher(rtf)模板开发语法大全(转)