第十一章 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;
this.name = 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()
}
}