1.Io流是什么:
通过字面可以将Io拆解为Input和Output,分别是输入和输出的意思。
比如:我们可以将学习的知识理解为输入到自己大脑,而将所学的知识运用在生活中或者考试这样便是输出。
Java中IO是java.io包下的一些常用类的使用,通过常用类对数据的读取(输入Input)和写出(输出Output)
2.为什么学习Io流:
存在的问题:做快递E栈项目时,自己深有感触,当程序运行时,所有的快递信息都在内存中。关闭程序后,这些快递信息就会丢失。
如何解决:使用Io流将快递信息保存在本地磁盘中,下次启动程序后通过Io操作(反序列化)将快递信息读取到内存。删除、修改、查看快递信息通过Io操作(序列化),重新写入到磁盘中。
2.1.Io流分类:
按照流动的数据类型可以分为: 字节流、字符流
按照流动的的方向来可以分为: 输入流、输出流
通过输入流把硬盘的文件输入到(Java)内存中
通过输出流把字节写到硬盘中
既然Io流是对数据的读取和写出。那么,数据存储的位置是需要去明确的。
学习File类必不可少,需要通过它去创建存储数据的文件。
2.2File类:
API中有这么一句话:
- 文件系统可以对实际的文件系统对象上的某些操作实施限制,例如读取,写入和执行。
注意:文件夹包含文件
常用的方法1:
File(String pathname)
通过将给定的路径名字符串创建新的 File实例。
//判断文件或目录是否存在
boolean exists()
//文件不存在就创建
boolean createNewFile()
//创建单级文件夹
boolean mkdir()
//创建单级文件夹
boolean mkdirs()
//是否是文件
boolean isFile()
//是否是文件夹
boolean isDirectory()
//删除文件或文件夹
boolean delete()
//获取路径
String getPath()
//判断是否是绝对路径
boolean isAbsolute()
//获取绝对路径
String getAbsolutePath()
//获取文件件内容从的长度
long length()
举例:
File file = new File("d://aaa");
file.mkdir();
File file1 = new File(file,"bbb.txt");
boolean flag = file1.createNewFile();
System.out.println(flag?"创建成功":"创建失败");//创建成功
String name = file1.getName();
System.out.println(name);//bbb.txt
//先执行mkdir查看能否创建多级目录
File file1 = new File("d://8-18/study");
if (!file1.exists()) {
//虽然if条件为true但是mdkir创建不了多级目录
file1.mkdir();
System.out.println("创建成功");
}else{
System.out.println("创建失败");
}
//mkdirs可以创建多级目录
File file2 = new File("d://8-18/study");
if (!file2.exists()) {
file2.mkdirs();
System.out.println("创建成功");
}else{
System.out.println("创建失败");
}
常用的方法2:
String[] list()
File[] listFiles()
boolean renameTo(File dest)
遍历所有文件:
File file = new File("d://8-18/study");
//获取文件夹中所有文件信息
String[] list = file.list();
for (int i = 0; i < list.length; i++) {
System.out.println(list[i]);
}
//获取带有路径的文件夹中所有文件信息
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
练习:查找后缀是MP4的文件 (假设不知道MP4视频放在那个文件夹里的)
网上下载一些MP4格式(视频)、MP3格式(音乐)、txt、docx等文件,目的是为了增加查找MP4文件的难度。
代码:
public class ExerTest {
public static void main(String[] args) {
File file = new File("D://");
//获取D盘所有文件夹
File[] files = file.listFiles();
queryMp4File(files);
}
/**
* 获取后缀格式是mp3的所有文件
* @param files D盘所有文件夹
*/
public static void queryMp4File(File[] files){
//判断是否是文件 如果是就输出该文件 如果不是就继续筛查
if (files!=null && files.length>0){
for (File file : files) {
if (file.isFile()){
if (file.getName().endsWith(".mp3")){
System.out.println(file.getAbsolutePath());
}
}else {
File[] files1 = file.listFiles();
queryMp4File(files1);
}
}
}
}
}
结果:
d:\收藏\视频\周杰伦\听妈妈的话.mp4
d:\收藏\视频\周杰伦\夜曲.mp4
d:\收藏\视频\周杰伦\红尘客栈.mp4
d:\收藏\视频\周杰伦\给我一首歌的时间.mp4
2.3OutputStream类和InputStream类
源码中可以看出OutputSteam类是一个抽象类所有无法直接使用。
public abstract class OutputStream implements Closeable, Flushable {}
OutputSteam提供了一些子类供我们使用。
字节流
FileOutputStream类
常用是FileOutputStream类,先来看看构造方法。
FileOutputStream(File file)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(File file, boolean append)
创建文件输出流以写入由指定的 File对象表示的文件。
FileOutputStream(String name)
创建文件输出流以指定的名称写入文件。
FileOutputStream(String name, boolean append)
创建文件输出流以指定的名称写入文件。
//如果c.txt不存在直接创建
FileOutputStream fos = new FileOutputStream("d:c.txt");
public FileOutputStream(File file) throws FileNotFoundException {
//调用二个参数的构造器
this(file, false);
}
//具体实现逻辑这里就不粘贴了
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
{
}
//如果File文件不存在,直接创建文件
File file = new File("d:aa.txt");
FileOutputStream fos = new FileOutputStream(file);
//通过源码可知通过参数name创建的输出流实际上底层也去创建了一个File对象
public FileOutputStream(String name) throws FileNotFoundException {
//这里依然调用的是上面的二参构造器 通过匿名对象初始化name的值。
this(name != null ? new File(name) : null, false);
}
下面通过具体的代码演示二参构造器,其中 参数 boolean append的意思。
操作代码:
void write(int b)
将指定的字节写入此文件输出流。
//d盘创建一个exer.txt文件
FileOutputStream fos = new FileOutputStream("d:exer.txt");
//为什么可以写入a,是因为字符a对应的ASCII是97
//对应的二进制(计算机存储的数据都是二进制形式)是0110 0001 一个字节=8 bit
fos.write((int)'a');
fos.write((int)'b');
fos.write((int)'c');
//使用完流必须关闭
fos.close();
//以上代码做个变化 其中true代表的是往exer.txt文件中追加数据
//d盘创建一个exer.txt文件
FileOutputStream fos = new FileOutputStream("d:exer.txt",true);
//为什么可以写入a,是因为字符a对应的ASCII是97
//对应的二进制(计算机存储的数据都是二进制形式)是0110 0001 一个字节=8 bit
fos.write((int)'a');
fos.write((int)'b');
fos.write((int)'c');
//使用完流必须关闭
fos.close();
void write(byte[] b)
将 b.length个字节从指定的字节数组写入此文件输出流。
//还是往exer.txt文件中写入数据,不追加数据,执行完成后会清空上次的内容。
FileOutputStream fos = new FileOutputStream("d:exer.txt");
//通过字符串转换为字节数组
byte[] bytes = "abcdefg".getBytes();
fos.write(bytes);
fos.close();
void write(byte[] b, int off, int len)
将 len字节从位于偏移量 off的指定字节数组写入此文件输出流。
通俗的来讲:参数off代表代表索引,参数len代表长度
@Test
public void test2() throws IOException {
FileOutputStream fos = new FileOutputStream("d:exer.txt");
//通过字符串转换为字节数组
byte[] bytes = "abcdefg".getBytes();
fos.write(bytes,1,2);
fos.close();
}
//最后记得使用完流一定要关闭
void close()
关闭此文件输出流并释放与此流相关联的任何系统资源。
FileInputStream类
//int read()
//从该输入流读取一个字节的数据。
@Test
public void test3() throws IOException {
FileInputStream fis = new FileInputStream("d:exer.txt");
int read = fis.read();
int read2 = fis.read();
int read3 = fis.read();
int read4 = fis.read();
System.out.println((char)read);//a
System.out.println((char)read2);//f
System.out.println((char)read3);//g
//读取到末尾返回-1
System.out.println(read4);//-1
fis.close();
}
int read(byte[] b)
从该输入流读取最多 b.length个字节的数据为字节数组。
@Test
public void test4() throws IOException {
FileInputStream fis = new FileInputStream("d:exer.txt");
//数据缓冲区 一次缓冲2个字节数据
byte[] bytes = new byte[2];
//也就是说一次读取两个字节数据
fis.read(bytes);
//读到数组中的数据转化为字符串
System.out.println(new String(bytes));
fis.close();
}
@Test
public void test5() throws IOException {
FileInputStream fis = new FileInputStream("d:exer.txt");
byte[] bytes = new byte[2];
//循环读取
while (true){
//len的值为读取到的字节个数 与数组长度对应
int len = fis.read(bytes);
if (len!=-1){
System.out.println(new String(bytes,0,len));
}else {
break;
}
}
fis.close();
}
完成:对mp3格式的歌曲进行复制
@Test
public void test6() throws IOException {
FileInputStream fis = new FileInputStream("d:\\收藏\\视频\\周杰伦\\你就不要想起我.mp3");
//将文件复制到桌面
FileOutputStream fos = new FileOutputStream("C:\\Users\\Lenovo\\Desktop\\你就不要想起我.mp3");
//一次读5MB大小的数据,缓存到字节数组中
byte[] bytes = new byte[1024 * 1024 * 5];
int len = 0;
while ((len=fis.read(bytes))!=-1){
//写入到指定路径 从0索引开始,到实际读到的len长度(歌曲的字节数)
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}
字节流读取汉字:
@Test
public void test7() throws IOException {
FileInputStream fw = new FileInputStream("d://b.txt");
int read3 = fw.read();
int read2 = fw.read();
int read1 = fw.read();
int read = fw.read();
System.out.println((char)read3);
System.out.println((char)read2);
System.out.println((char)read1);
System.out.println((char)read);
fw.close();
}
通过可以看出读取到的汉字乱码
出现乱码原因txt文本与idea的编码格式不一致。
使用字符流解决该问题或者指定文本编码格式。
另外存在另一个问题是读取不到一个完整的汉字。在字符流中解决这个问题
@Test
public void test() throws IOException {
FileInputStream fis = new FileInputStream("d://a.txt");
//一次读取二十个字节的汉字
byte[] bytes = new byte[20];
while (true){
int len = fis.read(bytes);
if (len==-1){
break;
}
System.out.println(new String(bytes,0,len));
}
}
2.4Writer类和Reader类
字符流
FileWriter类
API里构造方法:
FileWriter(File file)
给一个File对象构造一个FileWriter对象。
FileWriter(File file, boolean append)
给一个File对象构造一个FileWriter对象。 。
FileWriter(String fileName)
构造一个给定文件名的FileWriter对象。
FileWriter(String fileName, boolean append)
构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。
测试:
public void write(int c)throws IOException
一次写一个字符
@Test
public void test8() throws IOException {
FileWriter fw = new FileWriter("d://a.txt");
fw.write('中');
fw.write('国');
fw.write('加');
fw.write('油');
fw.close();
}
public void write(String str) throws IOException {
写入字符串
测试代码:
@Test
public void test9() throws IOException {
FileWriter fw = new FileWriter("d://a.txt");
fw.write("abcdefgh");
fw.close();
}
public Writer append(CharSequence csq) throws IOException
追加内容:
StringBuffer与FileWriter append方法比较:
相同点:
StringBuffer返回的是调用该方法的对象
FileWriter 返回的也是调用该方法的对象
不同地点:
StringBuffer append()返回值类型是StringBuffer
FileWriter append()返回值类型是Writer(多态的形式)
@Test
public void test10() throws IOException {
FileWriter fw = new FileWriter("d://a.txt");
fw.append("每天都是充实的一天").append("开开心心最重要!");
fw.close();
}
FileReader类
public int read(char cbuf[]) throws IOException
将字符读入数组。
@Test
public void test2() throws IOException {
FileReader fr = new FileReader("d://a.txt");
//一次读取10个字符
char[] chars = new char[10];
while (true){
int len = fr.read(chars);
if (len==-1){
break;
}
System.out.println(new String(chars,0,len));
}
fr.close();
}
注意:字符输出流操作完后记得关闭,或者fr.flush();
字节转字符流
字节输出流—>字符输出流
@Test
public void test3() throws IOException {
FileOutputStream fos = new FileOutputStream("d://a.txt");
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write("梅花香自苦寒来");
osw.write("宝剑锋从磨砺出");
osw.close();
}
字节输入流—>字符输入流
@Test
public void test4() throws IOException {
FileInputStream fos = new FileInputStream("d://a.txt");
InputStreamReader is = new InputStreamReader(fos);
//一次读取七个字符
char[] chars = new char[7];
int len = 0;
while ((len=is.read(chars))!=-1){
System.out.println(new String(chars,0,len));
}
}
Print与BufferedReader
PrintStream类和PrintWriter类
@Test
public void test5() throws IOException {
PrintStream ps = new PrintStream("d://c.txt");
ps.print("啊哈哈哈哈哈");
ps.print("呵呵呵呵呵呵");
PrintWriter pw = new PrintWriter("d://c.txt");
pw.println("床前明月光");
pw.println("疑是地上霜");
//记得刷新流或者直接调用close() 否则没有数据
pw.flush();
pw.close();
}
BufferedReader缓存读取流
缓存读取流,将字符 输入流转换为带有缓存,可以一次读取一行的缓存的字符流
@Test
public void test6() throws IOException {
FileReader fw = new FileReader("d://c.txt");
BufferedReader buffer = new BufferedReader(fw);
String text = buffer.readLine();
System.out.println(text);
}
PrintStream ps = new PrintStream("d://c.txt");
ps.print("啊哈哈哈哈哈");
ps.print("呵呵呵呵呵呵");
PrintWriter pw = new PrintWriter("d://c.txt");
pw.println("床前明月光");
pw.println("疑是地上霜");
//记得刷新流或者直接调用close() 否则没有数据
pw.flush();
pw.close();
}
BufferedReader缓存读取流
缓存读取流,将字符 输入流转换为带有缓存,可以一次读取一行的缓存的字符流
@Test
public void test6() throws IOException {
FileReader fw = new FileReader("d://c.txt");
BufferedReader buffer = new BufferedReader(fw);
String text = buffer.readLine();
System.out.println(text);
}