第十一章 IO流
1.File类的使用
- java.io.File 类:**文件和文件目录路径**的抽象表示形式,和平台无关,声明在java.io下
- File 能新建、删除、重命名文件和目录,但是 File 不能访问文件内容本身,如需要访问文件内容,需要借助输入/输出流
- 想要在Java程序中表示一个真实存在的文件或目录,name必须有一个File对象,但是在Java程序中的一个File对象,可能没有一个真实存在的文件或目录
- File 对象可以作为参数传递给li流的构造器
1.1 File 类的常用方法
- 创建 File 类的对象
- 相对路径 :相较于某个路径下,指明的路径
- 绝对路径:包含盘符在内的文件或文件目录的路径
- 在Windows下路径分隔符用 / 在UNIX下用 \
- 为了避免在不同操作系统出现混淆,java 提供了一个常量,根据操作系统,动态提供分隔符 public static final String separator
//构造器一 File(String filePath)
//相对路径
File file1 = new File("Hello.txt");
//绝对路径
File file2 = new File("D:\\Study\\java\\java培训详细版.md");
//使用常量的方式
//"D:" + File.separator + "Study" +File.separator + "java" File.separator + "java培训详细版.md"
//构造器二 File(String parentPath,String childPath)
File file3 = new File("D:\\Study\\java","Test");
//构造器三 File(File parentFile,String childPath)
File file4 = new File(file3,"tset.txt");
- 获取绝对路径 getAbsolutePath()[一等优先级]
//public String getAbsolutePath()
System.out.println(file1.getAbsolutePath());
- 获取相对路径 getPath()[一等优先级]
//public String getPath()
System.out.println(file1.getPath());
- 获取名称 getName()[一等优先级]
//public String getName()
System.out.println(file1.getName());
- 获取上层文件目录路径,没有返回null getParent()[一等优先级]
//public String getParent()
System.out.println(file1.getParent());
- 获取文件字节总数 length()[一等优先级]
//public long length()
System.out.println(file1.length());
- 获取最后一次修改时间 毫秒值 lastModified()[一等优先级]
//public long lastModified()
System.out.println(new Date(file1.lastModified());
以下两个方法适用于文件目录
- 获取指定目录下所有文件或文件目录的名称数组 list()[特等优先级]
//public String[] list()
File file4 = new File("D:\\study");
String[] list = file.list();
for(String s : list){
System.out.println(s);
}
- 获取指定目录下的所有文件或目录的File数组listFiles()[特等优先级]
//public File[] listFiles()
File[] fs = file4.listFiles();
for(File f : fs){
System.out.println(f);
}
- 得到当前系统的所有根目录listRoots()[特等优先级]
//public static listRoots
File[] fs = File.listRoots();
- 把文件重命名为指定的文件路径 renameTo()[高危]
//public boolean renameTo(File dest)
File f1 = new File("hello.txt");
File f2 = new File("D:\\Study\\hello.txt");
boolean re = f1.renameTo(f2);
System.out.println(re);
/*
要想保证是true,需要 f1 在硬盘中存在的,且 f2 不能再硬盘中存在
*/
2. File类的判断功能
- 是否是文件目录 isDirectory()[一等优先级]
//public boolean isDirectory()
File f1 = new File("hello.txt");
System.out.println(f1.isDirectory());//false
- 是否是文件 isFile()[一等优先级]
System.out.println(f1.isFile());
- 是否存在 exists()[一等优先级]
System.out.println(f1.exists());
- 是否可读 canRead()
System.out.println(f1.canRead());
- 是否可写 canWrite()
System.out.println(f1.canWrite());
- 是否隐藏 isHidden()
System.out.println(f1.isHidden);
3. File类的创建删除功能
方法 |
作用 |
createNewFile() |
创建文件,如果存在返回false不进行创建 |
mkdir() |
创建文件目录,存在则不创建 |
mkdirs()[高危] |
创建文件目录,如果上一级目录不存在,一并创建 |
delete()[高危] |
删除文件或文件夹,不经过回收站 |
File file = new File("hi.txt");
if(!file.exists()){
file.createNewFile();
}else{
file.delete();
}
File file1 = new File("D:\\io\\io1 ");
file1.mkdir();
file1.mkdirs();
例题
判断指定目录下是否有.jpg文件,如果有输出文件名
import java.io.*;
public class JpgTest{
public static void main(String[] args){
File srcFile = new File("D:\\Study");
String[] fileNames = srcFile.list();
for(String name : fileNames){
if(name.endsWith(".jpg")){
System.out.println(name);
}
}
}
}
遍历指定目录下所有文件名称,包括文件目录中的文件
import java.io.*;
public class FileTest{
public static void main(String[] args){
File dir = new File("D:\\Study\\Yitu");
printSubFile(dir);
}
private static void printSubFile(File dir){
File[] subFiles = dir.listFiles();
for(File f : subFiles){
if(f.isDirectory()){
printSubFile(f);
}else{
System.out.println(f.getAbsolutePath());
}
}
}
}
2. IO流原理及流的分类
- 用于**处理设备之间的数据传输**,如读/写文件、网络通讯等
- java程序中,对于数据的输入/输出操作以**流(Stream)**的方式进行
- java.io 包下提供了各种 “ 流” 类的接口,用一获取不同种类的数据,并通过**标准的方法**输入或输出数据
- 流的分类
- 按操作数据单位不同:字节流(8 bit)、字符流(16 bit)
- 按数据流的流向不同:输入流、输出流
- 按流的角色不同分为:节点流、处理流
- 字节流读取中文会乱码,因为一个中文占用两个字节,所以需要用字符流读取
抽象基类 |
字节流 |
字符流 |
输入流 |
InputStream |
Reader |
输出流 |
OutputStream |
Writer |
分类 |
字节输入流 |
字节输出流 |
字符输入流 |
字符输出流 |
抽象基类 |
InputStream |
OutputStream |
Reader |
Writer |
访问文件 |
FileInputStream |
FileOutputStream |
FileReader |
FileWriter |
访问数组 |
ByteArrayInputStream |
ByteArrayOutputStream |
CharArrayReader |
CharArrayWriter |
访问管道 |
PipedInputStream |
PipedOutputStream |
PipedReader |
PipedWriter |
访问字符串 |
StringReader |
StringWriter |
||
缓冲流 |
BufferedInputStream |
BufferedOutputStream |
BufferrdReader |
BufferedWriter |
转换流 |
InputStreamReader |
OutputStreamWriter |
||
对象流 |
ObjectInputStream |
ObjectOutputStream |
||
**** |
FilterInputStream |
FilterOutputStream |
FilterReader |
FilterWriter |
打印流 |
PrintStrem |
PrintWriter |
||
推回输入流 |
PushbackInputStream |
PushbackReader |
||
特殊流 |
DataInputStream |
DataOutputStream |
2.1FileInputStream/FileOutputStream
- try-catch-finally
import java.io.*;
public class TestFileCopy{
public static void main(String[] args) throws IOException{
FileInputStream fis = null;
FileOutputStream fos = null;
try{
fis = new FileInputStream("DNF - 痛苦之村列瑟芬.mp3");
fos = new FileOutputStream("DNF - 痛苦之村列瑟芬1.mp3");
byte[] data = new byte[3 << 20];
int len;
while((len = fis.read(data)) != -1){
fos.write(data,0,len);
}
//太慢了
/*
while((data = fis.read()) != -1){
fos.write(data);
}
*/
}catch(IOException e){
e.printStackTrace();
}finally{
try{
fis.close();
}catch(IOException e){
e.printStackTrace();
}finally{
try{
fos.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}
- TWR 7.0新特性[超级重要🐴]
import java.io.*;
public class TestFileCopyWithTWR{
public static void main(String[] args){
try(FileInputStream fis = new FileInputStream("1.jpg");FileOutputStream fos = new FileOutputStream("2.png")){
byte[] data = new byte[1024];
int len;
while((len = fis.read(data)) != -1){
fos.write(data,0,len);
}
}catch(IOException e){
e.printStackTrace();
}
}
}
- FileOutputStream的构造方法
FileOutputStream( File f / String name) 这种模式如果有文件则会把源文件删除,在创建新的文件。想要在源文件的基础上追加文件则需要用 FileOutputStream(File f,true)
3 节点流
3.1 FileReader / FileWriter
- FileReader
- read() 返回读入的一个字符,如果达到文件末尾,则返回 -1
- 为了保证流资源一定会执行关闭操作,并需用try-catch-finally捕获异常
import java.io.*;
public class FileReaderTest{
@Test
public void test(){
File file = null;
FileReader fr = null;
try{
//1.实例化 File 类的对象,指明要操作的文件
file = new File("hi.txt");
//2.提供具体的流
fr = new FileReader(file);
//3.数据的读入
int data = fr.read();
while(data != -1){
System.out.print((char)data);
data = fr.read();
}
/*
int data;
while((data = fr.read()) != -1){
System.out.println((char)data);
}
*/
}catch(IOExecption){
e.printStackTrace();
}finally{
try{
//4.流的关闭
if(fr != null)
fr.close();
}catch(IOExecption){
e.printStackTrace();
}
}
}
//对 read() 操作升级,使用 read 的重载方法
@Test
public void testFileReader1{
File file = null;
FileReader fr = null;
try{
//1.File 类的实例化
file = new File("Hi.txt");
//2.FileReader流的实例化
fr = new FileReader(file);
//3.读入操作
//read(char[cbuf]):返回每次读入 cbuf数组中的字符串个数,如果达到文件末尾返回-1
char[] cbuf = new char[5];
int len;
while((len = file.read(cbuf)) != -1){
//方式一
for(int i = 0;i < len;i++){
System.out.print(cbuf[i]);
}
//方式二
String str = new String(cbuf,0,len);
System.out.print(str);
}
}catch(IOExecption e){
e.printStackTrace();
}finally{
//4.资源的关闭
}
}
}
- FileWriter
说明
- 输出操作,对应的 File 可以不存在,并不会报异常
- File 对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建这个对象
如果存在:①如果流使用的构造器是 FileWriter(file ,false) / FileWriter(file) ,对原有文件覆盖②如果使用的是 FileWriter(file,true) 不会对原有文件覆盖,而是在原有文件基础上追加内容
@Test
public void testFileWriter(){
File file = null;
FileWriter fw = null;
try{
//1. 提供 File 类对象,指明写出到的文件
file = new File("Hi1.txt");
//2.提供 FileWriter 的对象,用于数据写出
fw = new FileWriter(file,false);
//3.写出的操作
fw.write("Hello World!");
}catch(IOExecption e){
e.printStackTrace();
}fianlly{
fw.close();
}
}
使用 FileWriter 和 FileReader 实现文本文件的复制
import java.io.*;
//不能用字符流处理图片文件
public class TestFileCopy{
@Test
public void test(){
FileReader fr = null;
FileWriter fw = null;
try{
//1.创建 File 类的对象,指明读入和写出的文件
File srcFile = new File("Hei.txt");
File destFile = new File("Hi.txt");
//2.创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);
//3.数据输入输出操作
char[] c = new char[5];
int len;//记录每次读出来的字符个数
while((len = fr.read(c)) != -1){
//每次写出 len 个字符
fw.write(c,0,len);
}
}catch(IOExecption e){
e.printStackTrace();
}finally{
//4.资源的关闭
try{
if(fw != null)
fw.close();
}catch(IOExecption){
e.printStackTrace();
}finally{
try{
if(fr != null)
fr.close();
}catch(IOExecption){
e.printStackTrace();
}
}
}
}
}
对于文本文件**(.txt .java .c .cpp)**使用字符流处理,对于非文本文件使用字节流处理
3.2BufferedInputStream/BufferedOutputStream
- 提高流的读取,写入速度
- 实现非文本文件的复制
import java.io.*;
public class BufferedTest{
@Test
public void BUfferedTest(){
FileInuputStream fis = null;
FileInuputStream fis = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
//1.造 File 对象
File file1 = new File("hi.jpg");
File file2 = new File("hei.jpg");
//2.造流
//2.1 造节点流
fis = new FileInputStream(file1);
fis = new FileOutputStream(file2);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.读取写入
byte[] b = new byte[10];
int len;
while((len = bis.read(b)) != -1){
bos.writer(b,o,len);
}
}finally{
//4.资源关闭
//先关闭外层,再关内层
bos.close();
bis.close();
//关闭外层流的同时,内层流会自动关闭
fw.close();
fr.close();
}
}
}
3.3 DataInputStream/DataOutputStream
- 都属于**字节流、过滤流**
- 作为过滤流,是为了给原本的节点流添加读写基本数据类型的功能的
- 过滤流不能直接连接文件,只能连接其他的流
- **DataInputStream **不再以-1作为读取结束的标志。如果到了文件结果还尝试进行读取会导致EOFException -> EndOfFileException
import java.io.*;
public class TestDataStream{
public static void main(String[] args)throws Exception{
//我们想要把人物等级保存下来~等到明年春暖花开日 再继续游戏~
/*
int level = 7365;
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.data"));
dos.writeInt(level);
dos.close();
*/
DataInputStream dis = new DataInputStream(new FileInputStream("data.data"));
int x = dis.readInt();
dis.close();
System.out.println(x);
}
}
3.4 ObjectInputStream/ObjectOutputStream
- 同样是**字节流、过滤流**
- 为了给原本的节点流添加读取对象的功能的
- 如果到达文件结尾会触发EOFException
注意点
想要持久化一个对象 必须先要序列化这个类型
如果想要将A类的对象写出到磁盘当中 则A类必须实现序列化接口
implements Serializable
而如果A类当中还有其它引用类型的属性 则这些属性的类型
也要实现序列化接口 否则A对象持久化会出现异常
如果某些属性 无关紧要 不需要保存到文件当中
可以使用transient修饰
transient = 短暂的 转瞬即逝的 = 不参与持久化的
在写出一个对象的时候 transient的属性 将直接写出null
所以这个属性的类型 也就不需要序列化了~
import java.io.*;
import java.text.*;
public class TestObjectStream2{
public static void main(String[] args){
Wish myWish = new Wish("能早点在一起上课~网络教学就是坑!有个屁用!","5v");
System.out.println(myWish);
//请许下自己的愿望 并且将愿望保存在磁盘文件当中
try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("月光宝盒.data"))){
oos.writeObject(myWish);
}catch(Exception e){
e.printStackTrace();
}
}
}
class Wish implements Serializable{//愿望
String content;//愿望的内容
String name;//许愿人姓名
long time;//许下愿望的时间
public Wish(String content,String name){
this.content = content;
= name;
time = System.currentTimeMillis();
}
@Override
public String toString(){
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
return content + "\n\t\t\t" + name +"\n\t\t\t" + f.format(time);
}
}
4 字符流
Reader / Writer 是字符流的抽象基类
4.1FileReader/FileWriter
这两个类只能用来读取文本文件,但是字节流通用语所有文件
.txt .java .html .js .css .jsp .asp .php等
用法用FileInputStream / FileOutputStream类似
4.2 BufferedReader/BufferedWriter
- BufferedReader / BufferedWriter
- 给原本的流添加一个变长的缓冲空间,从而实现以行为单位的读取
- 文件结束返回null
import java.io.*;
public class TestBufferedWriter{
public static void main(String[] args)throws Exception{
//春眠不觉晓 处处闻啼鸟 夜来风雨声 花落知多少
BufferedWriter bw = new BufferedWriter(new FileWriter("鹅鹅鹅.txt"));
bw.write("鹅鹅鹅");
bw.newLine();//能够写出当前操作系统所匹配的换行标识
bw.write("鹅项向天歌");
bw.newLine();
bw.write("鹅毛浮绿水");
bw.newLine();
bw.write("鹅可能死了");
bw.close();
}
}
- PrintWiter
PrintWriter 和BufferedWriter 相比的优势
- PrintWriter既可以当做节点流 也可以当做过滤流,构造方法允许传入 File对象 / String路径 / 流!
- PrintWriter既可以连接字节流 又可以连接字符流,构造方法既可以传入 FileWriter 也可以传入 FileOutputStream
- 当做节点流使用的时候 构造方法第二个参数可以指定字符编码
new PrintWriter(“鹅鹅鹅.txt”,“utf-8”);- 当做过滤流使用的时候 构造方法第二个参数可以指定自动清空缓冲
new PrintWriter(new FileWriter(“abc.txt”),true);//autoFlush- 它的println() = write() + newLine()
import java.io.*;
public class TestPrintWriter{
public static void main(String[] args)throws Exception{
PrintWriter pw = new PrintWriter("春晓.txt");
pw.println("春眠不觉晓");//write()+newLine();
pw.println("处处闻啼鸟");
pw.println("夜来风雨声");
pw.print("花落知多少");
pw.close();
}
}
5. 转换流
- 转换流提供了在字节流和字符流之间的转换
- 通常使用转换流来处理文件乱码问题,
- 字节大输入流转换成字符输入流**InputStreamReader、字符输出流转换成字节输出流OutputStreamWriter**
public class InputStreamReaderTest{
public static void main(String[] args) throws IOExecption{
FileInputStream fis = new FileInputStream("Test.txt");
InputStreamReader isr = new InputStreamReader(fis);
char[] c = new char[10];
int len;
while((len = isr.read(c)) != -1){
String str = new String(c,0,len);
System.out.println(str);
}
isr.close()
}
}