Java-10-IO流
概述
大多数应用程序都需要实现与设备之间的数据传输,在Java中,将这种通过不同输入输出设备(键盘,内存,显示器,网络等)之间的数据传输抽象的表述为“流”,输入流和输出流是相对于内存设备而言的,将外设中的数据读取到内存中即输入,将内存的数据写入到外设中即输出。
四点明确
-
明确指定操作的数据是数据源(读)还是数据目的(写)
-
源:InputStream Reader
目的:OutStream Writer
-
-
明确要操作的设备上的数据是字节还是文本
-
源:
字节:InputStream
文本:Reader
目的:
字节:OutStream
文本:Writer
-
-
明确数据所在的具体设备
-
源设备:
硬盘:文件File开头
内存:数组,字符串
键盘:System.in
网络:Socket
目的设备:
硬盘:文件File开头
内存:数组,字符串
显示屏:System.out
网络:Socket
-
-
明确是否需要额外功能(exam:是否需要转换流,高校流)
File类
java.io.File类与流关,它操作的是文件本身(创建,查找和删除),而不是文件内容
用法
import java.io.File;
import java.io.IOException;
public class TestFile {
public static void main(String[] args) {
//=========File类的构造方法==========
//File类构造方法不会检验这个文件或文件夹是否真实存在,
//因此无论该路径下是否存在文件或者目录,
//都不影响File对象的创建。
//注意路径中的"\"是转义字符"\\"表示转义转义字符="\"
//注意路径不区分大小写
//直接传文件路径
String path = "E:\\testFile.txt";
File f1 = new File(path);
// 通过父路径和子路径字符串
String parent = "E:\\testFile";
String child = "firstFile.txt";
File f2 = new File(parent, child); //等价于E:\\testFile\\fisrtFile.txt
//通过父类File对象和子路径
File fatherobj = new File("E:\\testFile");
String childPath = "secondFile.txt";
File f3 = new File(fatherobj,childPath);//等价于E:\\testFile\\secondFile.txt
//=========File类的常用方法=========
System.out.println("文件的绝对路径:"+f2.getAbsolutePath());//文件的绝对路径:E:\testFile\firstFile.txt
System.out.println("文件的构造路径:"+f2.getPath());//文件的构造路径:E:\testFile\firstFile.txt
System.out.println("文件名称:"+f2.getName());//文件名称:firstFile.txt
System.out.println("文件长度:"+f2.length()+"字节");//文件长度:0字节
//=========File类的判断方法=========
//判断File表示的文件/目录是否存在
System.out.println(f1.exists());//true
//判断是否为目录
System.out.println(f1.isDirectory());//false
//判断是否为文件
System.out.println(f1.isFile());//true
//=========创建与删除=========
//createNewFile() 创建文件 这里会判断是否已经存在 存在:不创建并返回false,不存在:传建并返回true
try {
System.out.println(f1.createNewFile());
} catch (IOException e) {
e.printStackTrace();
}
//mkdir(),mkdirs() 创建目录 返回值同上,
// 另:mkdir:仅创建一级目录,
// mkdirs:创建由此File表示的目录,包括任何必需但不存在的父目录。推荐使用
File f4 = new File("E:\\testFile\\makeDir\\testMakeDirs");
System.out.println(f4.mkdirs());//true
//delete() 删除File所表示的目录/文件
//另:若为目录,必须为空,且删除的是最里层文件/目录
System.out.println(f1.delete());//true
System.out.println(f4.delete());//true
System.out.println(f4.delete());//false 已经不存在了
//=========目录的遍历=========
//根据返回的对象不同分为
//String---list() 名字
//File-----listFiles() File对象
//注意listFiles在获取指定目录下的文件或者文件夹时必须满足下面两个条件
//1,指定的目录必须存在
//2,指定的必须是目录。否则容易引发返回数组为null,出现NullPointerException异常
//本例基于本人的电脑 E:\FFOutput目录
File file = new File("E:\\AAA开发文档");
for (String name:file.list()) {
System.out.println(name);
/*
589397 《Android Studio开发实战 从零基础到App上线》源码.rar
631554 Android开发:从0到1.pdf
654431 Android开发实例大全 第2版.pdf
Android Studio开发实战:从零基础到App上线.pdf
第一行代码(附源码)
*/
}
for (File f:file.listFiles()) {
System.out.println(f);
/*
E:\AAA开发文档\589397 《Android Studio开发实战 从零基础到App上线》源码.rar
E:\AAA开发文档\631554 Android开发:从0到1.pdf
E:\AAA开发文档\654431 Android开发实例大全 第2版.pdf
E:\AAA开发文档\Android Studio开发实战:从零基础到App上线.pdf
E:\AAA开发文档\第一行代码(附源码)
*/
}
}
}
IO的分类
根据数据流向
- 输入流:设备->内存
- 输出流:内存->设备
根据数据类型
- 字节流:以字节为单位,读写数据的流
- 字符流:以字符为单位,读写数据的流。
对应的超类
输入流 | 输出流 | |
---|---|---|
字节流 | InputStream | OutputStream |
字符流 | Reader | Writer |
字节流
任何文件(文字,图片,视频…)都是一个一个字节
字节输出流(OutputStream)
OutputStream作为字节输出流所有子类的超类定义了如下共性方法
close() 关闭此输出流,并释放相关资源
flush() 刷新此输出流并强制任何缓冲输出字节被写出
write(byte[] b) 将b中的字节从指定字节数组写入此输出流
write(byte[] b, int offset, int len) 从指定的字节数组写入len字节,从偏移量offset开始输出到此输出
write(int b) 将指定的字节写入此文件输出流。----抽象类
文件输出流(FileOutputStream)
将数据(内存)写出到文件(硬盘)
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFileOutStream {
public static void main(String[] args) throws IOException {
//===========构造方法============
/*
创建输出流对象的时候,
系统会自动去对应位置创建对应文件,
如果已经有这个文件,会清空这个文件的数据。
*/
//根据File对象为参数创建FileOutStream类
File f1 = new File("E:\\testFile\\testFileOut.txt");
FileOutputStream fos = new FileOutputStream(f1);
//根据名称字符串为参数创建FileOutStream类 推荐
FileOutputStream fos2 = new FileOutputStream("E:\\testFile\\a.txt");
//===========写出字节流的方法(重载)=========
// int b Ascii码转字节
fos.write(97);//a
fos.write(98);//b
fos.write(99);//c
//字符串->字节数组
byte[] b = "hello my friends".getBytes();
//byte[] b 字节数组
fos.write(b);
//字节数组,指定片段
fos.write(b,6,10);
//关闭资源
fos.close();
fos2.close();
/*
* testFileOut.txt:
* abchello my friendsmy friends
* */
//============实现数据追加续写、换行===========
/*
由于使用之前的构造方法,创建FileOutStream类总会清除原始数据
利用以下构造方法实现追加(true 追加)
FileOutputStream(File file, boolean append)
FileOutputStream(String name, boolean append)
Windows换行则是 \n,\r
*/
FileOutputStream fos3 =new FileOutputStream(f1,true);
byte[] b2 = "\n我的前面应该有字节".getBytes();
fos3.write(b2);
fos3.close();
}
}
字节输入流(InputStream)
InputStream作为字节输入流所有子类的超类定义了如下共性方法
close() 关闭此输入流并释放相关系统资源。
abstract int read() 从输入流读取数据的下一个字节 抽象类
int read(byte[] b) 该方法返回的int值代表的是读取了多少个字节,读到几个返回几个,读取不到返回-1
文件输入流(FileInputStream)
读取文件(硬盘)内容
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class TestFileInputStream {
public static void main(String[] args) throws IOException {
//===========文件输入流的构造方法==============
/*
创建文件输入流时,如果参数 路径下没有该文件
会报错FileNotFoundException
*/
//File对象为参数创建FileInputStream类
File f1 = new File("E:\\testFile\\testFileIn.txt");
FileInputStream fis = new FileInputStream(f1);
//名称字符串为参数创建FileInputStream类 推荐
FileInputStream fis2 = new FileInputStream("E:\\testFile\\testFileIn.txt");
//============FileInputStream类读取字节方法===========
//int read() 每次可读取一个字节的数据,读到末尾返回-1
int read;
while ((read = fis2.read())!=-1){
System.out.print((char) read);//hello my friends
}
//int read(byte[] b) 每次读取b.lenth个字节到数组b中,返回读取到的有效字节个数,读取到末尾时,返回-1
int len;//接受返回的有效字节数
byte[] b = new byte[3];
while ((len = fis.read(b))!=-1){
System.out.println(new String(b));
//System.out.println(new String(b,0,len));可避免如下情况
/*
hel
lo
my
fri
end
snd //这里,多读了nd,
原因时最后一次仅有一个字符,
而上一个字符数组end,替换了e
还留下了nd
*/
}
fis.close();
fis2.close();
}
}
字节流综合实例(图片的复制)
创建数据流:
指定数据源
指定目的地
读写数据
定义数组容器
定义长度
循环读取
写出数据
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestOutAndIn {
public static void main(String[] args) throws IOException {
//确定数据源
FileInputStream fis = new FileInputStream("E:\\Pictures\\kaisa.jpeg");
//确定目的地
FileOutputStream fos = new FileOutputStream("E:\\testFile\\kaisacopy.jpeg");
//定义接受数组和返回值
byte[] b = new byte[1024];
int len;
while((len=fis.read(b))!=-1){
fos.write(b,0,len);
}
//关闭资源
fos.close();
fis.close();
}
}
字符流
按道理说文件都是字节,字节流应当够用了,但是由于文件的编码不同,字节流直接读取数据(比如中文)会有乱码的问题,所以需要字符流
处理纯文本的数据优先考虑字符流,其他情况用字节流了(图片、视频)。
字符流 = 字节流 + 编码表
字符输出流(Writer)
是字符输出流的所有类的超类,将指定的字符信息写出到目的地,共性方法如下
write(int c): 写入单个字符
write(char[] cbuf): 写入字符数组。
abstract void write(char[] cbuf, int off, int len): 写入字符数组的某一部分,off数组的开始索引,len写的字符个数
write(String str) 写入字符串
write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
flush() 刷新该流的缓冲
close() 关闭此流,但要先刷新它
import java.io.FileWriter;
import java.io.IOException;
public class TestFileWriter {
public static void main(String[] args) throws IOException {
//=======构造方法==========
/*
FileWriter(File file): 创建FileWriter,给定要读取的File对象。
FileWriter(String fileName):创建一个FileWriter,给定要读取的文件的名称。
* */
FileWriter fw = new FileWriter("E:\\testFile\\testFileWriter.txt");
fw.write(97);
fw.write('b');
fw.write("\n我是中国人!");
//关闭资源时,与FileOutputStream不同。 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
fw.close();
}
}
close和flush
因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。但是关闭的流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush方法。
flush()
:刷新缓冲区,流对象可以继续使用。
close()
:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TestFlush {
public static void main(String[] args) throws IOException {
//数据源
FileReader fr = new FileReader("E:\\testFile\\a.txt");
//目的地
FileWriter fw = new FileWriter("E:\\testFile\\b.txt");
int len;//接受放回值
while((len = fr.read())!=-1){
fw.write(len);
}
//这里是没有使用close关闭流
/*
* b.txt什么都没有
* 关闭资源时,与FileOutputStream不同。
* 如果不关闭,数据只是保存到缓冲区,并未保存到文件。
* */
fr.close();
fw.flush();
/*
* flush的作用:
* 用于清空缓冲区的数据流,进行流的操作时,数据先被读到内存中,
* 然后再用数据写到文件中,当你数据读完时,我们如果这时调用close()方法关闭读写流,
* 就可能造成数据丢失,因为读入数据完成时不代表写入数据完成,一部分数据可能会留在缓存区中
* */
fw.close();
}
}
FileWriter的续写和换行同FileOutputStream
字符流综合实例(复制文本)
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TestRAndW {
public static void main(String[] args) throws IOException {
//输入流对象
FileReader fr = new FileReader("E:\\testFile\\a.txt");
//输出流对象
FileWriter fw = new FileWriter("E:\\theCopyOfa.txt");
char[] c = new char[1024];//容器
int len;//
while ((len = fr.read(c))!=-1){
fw.write(c);
}
fw.flush();
fr.close();
fw.close();
}
}
字符输入流(Ritereader)
同理:Reader是字符输入流的所有类的超类,共性方法如下:
close(): 关闭此流并释放相关系统资源。
int read(): 从输入流读取一个字符。
int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组cbuf中
FileReader类
读取字符文件的便利类。构造时使用系统默认的字符编码和默认字节缓冲区。
import java.io.FileReader;
import java.io.IOException;
public class TestFileReader {
public static void main(String[] args) throws IOException {
//=======构造方法==========
/*
* FileReader(File file): 创建一个新的FileReader类,给定要读取的File对象。
* FileReader(String fileName): 创建一个新的FileReader类,给定要读取的文件的字符串名称。
* */
FileReader fr = new FileReader("E:\\testFile\\testFileReader.txt");
//定义变量,保存数据
int b;
while((b=fr.read())!=-1) {
System.out.println((char) b);
}
fr.close();
}
}
缓冲流
缓冲流,也叫高效流,是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类:
- 字节缓冲流: BufferedInputStream , BufferedOutputStream
- 字符缓冲流: BufferedReader , BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
字节缓冲流
构造方法
- public BufferedInputStream(InputStream in):创建一个新的缓冲输入流,注意参数类型为InputStream。
- public BufferedOutputStream(OutputStream out): 创建一个新的缓冲输出流,注意参数类型为OutputStream。
构造举例代码如下:
//构造方式一: 创建字节缓冲输入流【但是开发中一般常用下面的格式申明】
FileInputStream fps = new FileInputStream(b.txt);
BufferedInputStream bis = new BufferedInputStream(fps)
//构造方式一: 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("b.txt"));
///构造方式二: 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt"));
普通流vs缓冲流
package com.IO;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//普通流测试
public class TestNormal {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try (//创建文件输入流
FileInputStream fis = new FileInputStream("E:\\Pictures\\akali.jpg");
//创建文件输入流
FileOutputStream fos = new FileOutputStream("E:\\testFile\\copyakali.jpg");
){
//读写数据
int b;
while ((b=fis.read())!=-1){
fos.write(b);
}
fis.close();
fos.close();
}catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("普通流的复制时间:"+(end-start));
}
}
普通流的复制时间:8896
import java.io.*;
//缓冲流
public class TestBuffered {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Pictures\\akali.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\testFile\\copyakali2.jpg"));
){
int b;
while ((b=bis.read())!=-1){
bos.write(b);
}
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("缓冲流的复制时间:"+(end-start));
}
}
缓冲流的复制时间:93
用数组做容器更快
import java.io.*;
public class TestBuffered {
public static void main(String[] args) {
long start = System.currentTimeMillis();
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Pictures\\akali.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\testFile\\copyakali2.jpg"));
){
int len;
byte[] b = new byte[1024];
while ((len=bis.read(b))!=-1){
bos.write(b,0,len);
}
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("缓冲流的复制时间:"+(end-start));
}
}
缓冲流的复制时间:16
字符缓冲流
构造方法
- public BufferedReader(Reader in) :创建一个 新的缓冲输入流。
- public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。
构造举例,代码如下:
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
字符缓冲流特有方法
- BufferedReader:public String readLine(): 读一行数据。 读取到最后返回null
- BufferedWriter: public void newLine(): 换行,由系统属性定义符号。
readLine示例
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TestBufferReader {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("E:\\testFile\\a.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
// 循环读取,读取到最后返回null
while ((line = br.readLine())!=null) {
System.out.print(line);
System.out.println("------");
}
br.close();
}
}
newLine()示例
import java.io.*;
public class TestBufferReader {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\testFile\\testnewLine.txt"));
// 写出数据
bw.write("我");
// 写出换行
bw.newLine();
bw.write("是");
bw.newLine();
bw.write("中国人");
bw.newLine();
// 释放资源
bw.close();
}