IO流的使用和注意事项
File类的所使用的
1.File类的一个队形,代表一个文件或者一个文件目录(俗称:文件夹)
2.File类声明在java.io包下。
File类的创建的三种方式
import org.junit.Test;
import java.io.*;
public class FileTest {
/**
* 1.file类如何创建
* i>File(String filePath)
* ii>File(String parent , String childpath);
* iii>File(File parentFile,String childPath);
*
* 2.路径问题(相对路径和绝对路径)
* i>相对路径:相对于某个路径下,指明的路径
* ii>绝对路径:从本地盘符开始的文件目录路径
*
* 3.路径分隔符:
* windows:\\
* linux: /
*/
@Test
public void fileTest1(){
//构造器一:File(String filePath)
File file = new File("hello.txt"); //相对路径
File file1 = new File("D:\\he.txt");//绝对路径
//构造器二:File(String parent , String child); parent路径下的javaIdea目录
File file2 = new File("D:\\java","javaIdea");
System.out.println(file2); //运行结果: D:\java\javaIdea
//构造器三: File(File parentFile,String childPath); parentFile路径下的hello.txt文件
File file3 = new File(file2,"hello.txt");
System.out.println(file3); //运行结果: D:\java\javaIdea\hello.txt
}
}
File类的常用方法
/**
* File类的常用方法
* public String getAbsolutepath():获取绝对路径
* public String getPath(): 获取路径
* public String getName(): 获取名称
* public String getParent(): 获取上层文件目录路径。若无,返回null
* public long length(): 获取文件长度(即:字节数)。不能获取目录长度
* public long lastModified(): 获取文件最后一次修改时间,毫秒值
*如下两个方法试用于文件目录:
* public String[] list(): 获取指定目录下的所有文件或者文件目录的名称数组
* public File[] listfiles(): 获取之sing目录下的所有文件或者文件目录的File数组
*/
@Test
public void FileTest1(){
File file = new File("hello.txt");
File file1 = new File("D:\\io\\he.txt");
System.out.println(file.getAbsoluteFile()); //C:\Users\Jack\IdeaProjects\TreadLianxi\IO\hello.txt
System.out.println(file.getPath());//hello.txt
System.out.println(file.getName());//hello.txt
System.out.println(file.getParent());//null
System.out.println(file.length());//0 没有文件情况下为默认值
System.out.println(file.lastModified());//0
System.out.println("**************************");
System.out.println(file1.getAbsoluteFile());//D:\io\he.txt
System.out.println(file1.getPath());//D:\io\he.txt
System.out.println(file1.getName());//he.txt
System.out.println(file1.getParent());//D:\io
System.out.println(file1.length());//9
System.out.println(file1.lastModified());// 1579590343347
System.out.println("**************************");
//在路径不存在报错:java.lang.NullPointerException
File file2 = new File("D:\\FlashFXP");
String[] list = file2.list();
for (String s : list){ //遍历
System.out.println(s);
}
System.out.println("**************************");
File[] files = file2.listFiles();
for (File f: files){
System.out.println(f);
}
}
@Test
public void fileTest2(){
/**
* public boolean renameTo(File dest);把文件重命名为指定的文件路径
* 比如:file1.renameTo(file2)为例
* 要想保证返回是true,需要file1在银盘中存在的,且file2不能再硬盘存在
*/
File file1 = new File("D:\\io\\he.txt");
File file2 = new File("D:\\io\\hello.txt");
boolean isFile = file1.renameTo(file2);//吧file1的名字改成file2
System.out.println(isFile);
}
File类的判断功能的方法
/**
* public boolean isDirectory(); 判断是否是文件目录
* public boolean isFile(); 判断是否是文件
* public boolean exists();判断是否存在
* public boolean canRead();判断是否可读
* public boolean canWrite();判断是否可写
* public boolean isHidden();判断是否隐藏
*/
@Test
public void fileTest3(){
//针对文件
File file = new File("D:\\io\\hello.txt");
System.out.println(file.isDirectory());
System.out.println(file.isFile());
System.out.println(file.canRead());
System.out.println(file.canWrite());
System.out.println(file.isHidden());
//针对文件目录
System.out.println("*****************");
File file1 = new File("D:\\io\\");
System.out.println(file1.isDirectory());
System.out.println(file1.isFile());
System.out.println(file1.canRead());
System.out.println(file1.canWrite());
System.out.println(file1.isHidden());
//总结:在文件或者目录的路径是错误的情况下返回默认值false
}
File文件的创建和删除
/**
* 创建硬盘中对应的文件或文件目录
* public boolean createNewFile():创建文件。若文件存在,则不删除,返回false。
* public boolean mkdir(); 创建文件目录。如果此文件目录存在,就不创建,如果此文件
* 目录的上层目录不存在,也不创建
* public boolean mkdirs(); 创建文件目录。如果上层目录不存在一并创建
* public boolean delete(); 删除文件或者文件夹(删除的文件或目录不走回收站)
*/
@Test
public void fileTest4() throws IOException {
//文件的创建
File file = new File("D:\\io\\hello.txt");
if(!file.exists()){
boolean newFile = file.createNewFile();
System.out.println("创建成功");
}else{
boolean delete = file.delete();
System.out.println("删除成功");
}
}
@Test
public void fileTest5(){
//文件目录的创建
File file = new File("D:\\io\\hello.txt");
boolean mkdir = file.mkdir();
if(mkdir){
System.out.println("创建成功1");
}else{
System.out.println("常见失败");
}
File file1 = new File("D:\\io\\io11\\hello.txt");
boolean mkdirs = file1.mkdirs();
if (mkdirs){
System.out.println("创建成功2");
}else{
System.out.println("创建失败");
}
}
总结:在以上file类中设计到关于文件或者文件目录的创建、删除、重命名 、修改时间、文件大小等方法,并未涉及到写入或者读取文件内容的操作如果需要读取或写入文件内容,必须使用IO流来完成。后续File类的对象常作为参数传递到流的构造器中,指明读取或写入的“终点” 。下面就详细介绍下IO流的知识。
IO流的分类和结构体系
一、流的分类
1. 操作数据单位:字节流 、 字符流
2. 数据的流向: 输入流 、 输出流
3. 流的角色: 节点流 、 处理流
二、流的体系结构
抽象基类 | 节点流(文件流) | 缓冲流(处理流) |
---|---|---|
InputStream | FileInputStream | BufferedInputStream |
OutputStream | FileOutputStream | BufferedOnputStream |
Reder | FileReader | BufferedReader |
Writer | FileWriter | BufferedWriter |
字节流 | 字符流 |
---|---|
InputStream | Reder |
OutputStream | Writer |
字符流读取文件(最基本方式)
public class ReaderWirteTest {
@Test
public void testFileReder(){
FileReader fr = null;
try {
//1.实例化File类的对象,指明需要读取的文本
File file = new File("hello.txt");
System.out.println(file.getAbsoluteFile());
//2.提具体供流
fr = new FileReader(file);
//3.读文本文件
//read():返回读入的一个字符。如果达到文件末尾,返回-1
int read;
while((read=fr.read())!=-1){
System.out.print((char) read);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//4.关闭流
if(fr!=null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//对read()操作升级: 使用read的重载方法
@Test
public void testFileReder1(){
FileReader fileReader = null;
try {
//1.File文件的实例化
File file = new File("hello.txt");
//2.FileReader流的实例化
fileReader = new FileReader(file);
//3.读入的操作
char[] chars = new char[5];
int len ;
while ((len=fileReader.read(chars))!=-1){
//错误写法
/*for (int i =0 ; i<chars.length;i++){
System.out.println(chars[i]);
}*/
//正确
/*for(int i =0 ; i<len;i++){
System.out.print(chars[i]);
}*/
//错误写法
/* String str = new String(chars);
System.out.print(str);*/
//正确写法
String str = new String(chars,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭流
try {
if(fileReader!=null) {
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符流写入内容到文件(最基本方式)
/**
* 说明:
* 1. 输出操作,对应的File可以不存在,并不会报异常。
* 如果没有文件在写入操作会自动创建目标文件
* 2.File对应的硬盘中的文件如果存在:
* 如果流使用 的构造器是: FileWriter(file ,false)/FileWriter(file)
* 将会对原有的文本中内容进行覆盖。
* 如果流使用的构造器是: FileWriter(file,true)
* 不会覆盖原有文件内容只是在原有文件中的内容进行追加
*/
@Test
public void testFileWriter() throws IOException {
//1.提供File类对象,指明写出到的文件
File file = new File("hello.txt");
//2.提供FileWriter的对象,用于数据写出
FileWriter fw = new FileWriter(file);
//3.写出的操作 可以写字符串可以写字符数组
fw.write("I wished you love me");//写入字符串
fw.write("I have a dream!");
fw.write("you have need dream".toCharArray());//写入字符数组
//4.关闭流资源
fw.close();
}
字符流的读写整合(最基本方式)
@Test
public void ReaderWriterTest(){
FileReader fr= null ;
FileWriter fw= null ;
try {
//1.创建File类的对象,指明读入和写出的文件
File file = new File("hello.txt");
File file1 = new File("hello1.txt");
//2.创建输入和输出流的对象
fr = new FileReader(file);
fw = new FileWriter(file1);
//3.数据的读入和写出操作
//一次读入多个可用char数组
char[] chars = new char[5];
int len ;
while ((len = fr.read(chars))!=-1) {
fw.write(chars,0 ,len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//4.关闭流资源
try {
if(fr != null || fw!= null){
fr.close();
fw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意:对于文本文件(.txt,java,.c,cpp),使用字符流处理
对于非文本文件(.jpg,.mp3,mp4,avi,doc,.ppt)使用字节流处理。
字节流读写图片(最基本方式)
import org.junit.Test;
import java.io.*;
/**
* 测试FileInputStream 和 FileOutPutStream的使用
*/
public class FileInputAndFileOutputTest {
@Test
public void testFileInputStream(){
FileInputStream fis = null ;
FileOutputStream fos = null;
try {
//1.创建文件的对象。
File file = new File("timg.jpg");
File file1 = new File("timg1.jpg");
//2.创建读取文件的对象流
fis = new FileInputStream(file);
fos = new FileOutputStream(file1);
//3.读文件的操作
byte[] bytes = new byte[1024];//一次读取字节的长度,一般是1024的整数倍
int len ;//每次读取的字节个数
while ((len=fis.read(bytes))!=-1){
// 读取的过程
byte[] gbks = new String(bytes, 0, len).getBytes();
for (byte b : gbks){
System.out.print(b+" ");
}
//写出的过程
fos.write(bytes,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭资源
try {
if(fis != null || fos != null){
fis.close();
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲流(作用:提高文件的读写效率。)
非文本文件的读取和写入示例
import org.junit.Test;
import java.io.*;
/**
* 一、缓冲流:
* 1.字节缓冲流: BufferedInputStream 、 BufferedOutputStream
* 2.字符缓冲力: BufferedReader 、BufferedWriter
*
* 二、作用:
* 提供流的读取、写入的速度,提高文件的读写速度。
* BufferedXXXXStream在底层内部提供了一个缓冲区
* 缓冲区提供了一个flush() 主要作用是刷新缓冲区。
*/
public class BufferStreamTest {
/**
* 实现非文本文件的复制
*/
@Test
public void BufferedStreamTest(){
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.创建文件对象
File file = new File("timg.jpg");//读取的文件
File file1 = new File("timgWrite.jpg");//写入的文件对象
//2.创建输入输出流的对象
//2.1 基本的文件输出输入流
fis = new FileInputStream(file);
fos = new FileOutputStream(file1);
//2.2 常见文件的缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.读写的过程
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {
/*读取字节
byte[] bytes1 = new String(bytes).getBytes();
for(Byte b : bytes1){
System.out.print(b+" ");
}*/
bos.write(bytes, 0, len);
}
}catch (Exception e){
e.printStackTrace();
}finally {
//释放资源(要求:先关闭外层的流,在关闭内层的流)
try {
if(bos !=null || bis !=null) {
bos.close();
bis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
//说明:在关闭外层流的同时,内层流也会自动关闭
//fos.close();
//fis.close();
}
}
}
缓冲流读取文本(最基本的方式)
@Test
public void BufferedTest(){
FileReader fr = null;
FileWriter fw = null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件对象
File file = new File("hello.txt");//读取的目标文件
File file1 = new File("HelloTO.txt");//读取后写入的文件
//创建字符流对象
fr = new FileReader(file);//字符读入流
fw = new FileWriter(file1);//字符写入流
//创建缓冲流对象
br = new BufferedReader(fr);//读的缓冲流
bw = new BufferedWriter(fw);//写的缓冲流
//一次传输的字符长度
char[] chars = new char[1024];//读取的字符长度
int len;//记录的是否读取到文件尾部
while ((len=br.read(chars))!=-1){//循环读取
String s = new String(chars, 0, len);//读取的char转成字符串
System.out.println(s);
bw.write(chars,0,len);//缓冲流写出内容到文件
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
try {
if (br !=null || bw !=null ){
br.close();
bw.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
转换流的使用
转换流的解释:提供了字节流 和字符流之间的转换。
Java API提供了两个转换流:
InputStreamReader:将InputStream转换为Rreader
OutputStreamWriter:将Writer转换为OutputStream
字节流中的数据都是字符时,装成字符流操作更加高效。
很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
转换流的读取操作
@Test
public void InputStreamReader(){
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
long start = System.currentTimeMillis();
//常见读取文件对象
File file = new File("hello.txt");
//创建字节流读取对象
fis = new FileInputStream(file);
//创建转换流吧字节流转换成字符流
isr = new InputStreamReader(fis);//使用默认的字符集
//使用指定的字符集,具体是用哪个字符集取决于txt文件的保存时使用的字符集
// isr = new InputStreamReader(fis,"gbk");
//br = new BufferedReader(isr);转换流+字符缓冲区
int len ;
char[] chars = new char[1024];
while ((len = isr.read(chars))!=-1){
String s = new String(chars, 0, len);
System.out.println(s);
}
long end = System.currentTimeMillis();
System.out.println(end-start);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//释放资源
if (isr!=null || fis!=null){
isr.close();
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
转换流的读取整合(字节流读取文件控制台以字符流的形式输出,在写入的时候通过字节流写入转成字符流写到文件中)
@Test
public void InputStreamReaderAndOutputStreamWtriteTest(){
FileInputStream fis =null;
FileOutputStream fos = null;
InputStreamReader isr=null;
OutputStreamWriter osw=null;
try {
//创建文件读取和写入对象
File file = new File("hello.txt");
File file1 = new File("hellotxt.txt");
//创建读取和写入流的对象
fis = new FileInputStream(file);//字节输入流
fos = new FileOutputStream(file1);//字节输入流
//FileReader fr = new FileReader(file);//字符输入流
//FileWriter fw = new FileWriter(file1);//字节输出流
isr = new InputStreamReader(fis,"UTF-8");//字节转字符 转换流
osw = new OutputStreamWriter(fos,"GBK");
char [] chars = new char[1024];//读取的长度
int len ;
while ((len = isr.read(chars))!=-1){
String str = new String(chars , 0 ,len);
System.out.println(str);
osw.write(chars , 0 ,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(osw!=null||isr!=null||fos!=null||fis!=null){
osw.close();
isr.close();
fos.close();
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
对象流
*理解:*用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以吧Java中的对象写入到数据源中,也能吧对象从数据源中还原回来。
序列化: 用ObjectOutputStream类保存 基本类型数据或对象的机制。
反序列化: 用ObjectIutputStream类读取 基本类型数据或对象的机制。
注: ObjectOutputStream和ObjectIutputStream不能序列化static和transient修饰的成员变量。
对象流写入一个bat文件(序列化)
/**
* 序列化:将内存中的Java对象保存在磁盘中或者 通过网络传输出去
* 使用ObjectOutputStream实现
*/
@Test
public void ObjectOutputStream(){
//创建流
ObjectOutputStream oos = null;
FileOutputStream fos =null;
try {
File file = new File("hello.bat");
FileOutputStream fileOutputStream = new FileOutputStream(file);
oos =new ObjectOutputStream(fileOutputStream);
//写数据
oos.writeObject(new String("我爱北京天纳闷"));
oos.flush();//刷新操作
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象流的读取(反序列化)
/**
* 反序列化:将磁盘文件中的对象还原为内存中的一个java对象
* 使用ObjectInputStream
*/
@Test
public void testObjectInputStream(){
ObjectInputStream ois = null;
try {
File file = new File("hello.bat");
FileInputStream fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
String str = (String) obj;
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象流读取写入自定义的对象
@Test
public void ObjectOutputStream(){
//创建流
ObjectOutputStream oos = null;
FileOutputStream fos =null;
try {
File file = new File("hello.bat");
FileOutputStream fileOutputStream = new FileOutputStream(file);
oos =new ObjectOutputStream(fileOutputStream);
//写数据
oos.writeObject(new String("我爱北京天纳闷"));
oos.flush();//刷新操作
//创建自定义的类的
oos.writeObject(new Person("肺炎",12));//创建自定义类的对象Person并写入
oos.flush();//刷新操作
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();//关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void testObjectInputStream(){
ObjectInputStream ois = null;
try {
File file = new File("hello.bat");
FileInputStream fis = new FileInputStream(file);
ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
String str = (String) obj;
Person person = (Person) ois.readObject();//读取写入的自定义的对下那个
String str1 = new String(person.toString());//对象转成字符串
System.out.println(str+" "+str1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
总结: 流的操作在我们日常开发中是经常使用到的,对于流的操作也是无处不在,因此我们需要掌握,简单总结下对于流的操作步骤:
1.创建读取/写入的文件对象 一般是File类
2.创建操作File类的文件对象流:主要包含字符流(FileReader和FileWriter )字节流(FileInputStream和FileOutputStream)。根据开发场景选取所使用的对象流,文本文件通常使用字符流,非文本文件一般使用字节流。
3.在选好操作的字节/字符流对象以后,我们可以根据场景选取缓冲流对象(BufferedInputStream/BufferedOutputStream或者BufferedReader和BufferWriter)。
3.1附加步骤:根据选取的流不同,增加流读取写入的速度我们通常对流的读取长度进行定义:
字节流: Byte[] bytes = new Byte[1024n];
字符流:Char[] chars = new Char[1024n];
通常长度是1024的整数倍。
4.释放流资源。
掌握以上四步对流的操作就易如反掌。任何流的操作都满足以上四步。
最后欢迎广大博友来指点一二。