File类
- java.io.File类: 文件和文件目录路径的抽象表示形式,与平台无关
- File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
- 想要在Java程序中表示一个真实存在的文件或目录,那么必须有一个File对象,但是Java程序中的一个File对象,可能没有一个真实存在的文件或目录。
- File对象可以作为参数传递给流的构造器
File类的常用方法
构造器:
- public File(String pathname)
以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。
绝对路径: 是一个固定的路径,从盘符开始
相对路径: 是相对于某个位置开始 - public File(String parent,String child)
以parent为父路径, child为子路径创建File对象。 - public File(File parent,String child)
根据一个父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()
获取指定目录下的所有文件或者文件目录的File数组
重命名功能:
- public boolean renameTo(File dest)
把文件重命名为指定的文件路径
File类的判断功能:
- public boolean isDirectory()
判断是否是文件目录 - public boolean isFile() :
判断是否是文件 - public boolean exists() :
判断是否存在 - public boolean canRead() :
判断是否可读 - public boolean canWrite() :
判断是否可写 - public boolean isHidden() :
判断是否隐藏
File类的创建功能:
- public boolean createNewFile() :
创建文件。 若文件存在, 则不创建, 返回false - public boolean mkdir() :
创建文件目录。 如果此文件目录存在, 就不创建了。
如果此文件目录的上层目录不存在, 也不创建。 - public boolean mkdirs() :
创建文件目录。 如果上层文件目录不存在, 一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径, 那么, 默认在项目路径下。
File类的删除功能:
- public boolean delete()
删除文件或者文件夹
删除注意事项:
1、Java中的删除不走回收站。
2、要删除一个文件目录, 请注意该文件目录内不能包含文件或者文件目录
IO流
- I/O是Input/Output的缩写, I/O技术是非常实用的技术, 用于处理设备之间的数据传输。 如读/写文件,网络通讯等。
- Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
输入input: 读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
输出output: 将程序(内存)数据输出到磁盘、光盘等存储设备中。
流的分类:
- 按操作数据单位不同分为:字节流(8bit),字符流(16bit)
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色的不同分为:节点流,处理流
节点流:直接从数据源或目的地读写数据
处理流:不直接连接到数据源或目的地,而是“连接” 在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
- Java的IO流共涉及40多个类,实际上非常规则,都是从如下4个抽象基类派生的
- 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
IO流体系
Reader
- int read()
读取单个字符。 作为整数读取的字符, 范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码) , 如果已到达流的末尾, 则返回 -1 - int read(char[] cbuf)
将字符读入数组。 如果已到达流的末尾, 则返回 -1。 否则返回本次读取的字符数。 - int read(char[] cbuf,int off,int len)
将字符读入数组的某一部分。 存到数组cbuf中, 从off处开始存储, 最多读len个字符。 如果已到达流的末尾, 则返回 -1。 否则返回本次读取的字符数。 - public void close() throws IOException
关闭此输入流并释放与该流关联的所有系统资源。
InputStream
-
int read()
从输入流中读取数据的下一个字节。 返回 0 到 255 范围内的 int 字节值。 如果因为已经到达流末尾而没有可用的字节, 则返回值 -1。 -
int read(byte[] b)
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 如果因为已经到达流末尾而没有可用的字节, 则返回值 -1。 否则以整数形式返回实际读取的字节数。 -
int read(byte[] b, int off,int len)
将输入流中最多 len 个数据字节读入 byte 数组。 尝试读取 len 个字节, 但读取的字节也可能小于该值。 以整数形式返回实际读取的字节数。 如果因为流位于文件末尾而没有可用的字节, 则返回值 -1。 -
public void close() throws IOException
关闭此输入流并释放与该流关联的所有系统资源。
OutputStream
- void write(int b)
将指定的字节写入此输出流。 write 的常规协定是:向输出流写入一个字节。 要写入的字节是参数 b 的八个低位。 b 的 24 个高位将被忽略。 即写入0~255范围的。 - void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。 write(b) 的常规协定是:应该与调用 write(b, 0, b.length) 的效果完全相同。 - void write(byte[] b,int off,int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。 - public void flush()throws IOException
刷新此输出流并强制写出所有缓冲的输出字节, 调用此方法指示应将这些字节立
即写入它们预期的目标。 - public void close() throws IOException
关闭此输出流并释放与该流关联的所有系统资源。
Writer
- void write(int c)
写入单个字符。 要写入的字符包含在给定整数值的 16 个低位中, 16 高位被忽略。 即写入0 到 65535 之间的Unicode码。 - void write(char[] cbuf)
写入字符数组。 - void write(char[] cbuf,int off,int len)
写入字符数组的某一部分。 从off开始, 写入len个字符 - void write(String str)
写入字符串。 - void write(String str,int off,int len)
写入字符串的某一部分。 - void flush()
刷新该流的缓冲, 则立即将它们写入预期目标。 - public void close() throws IOException
关闭此输出流并释放与该流关联的所有系统资源。
注意:不管任何类型的流,主要就四步(或者三步,合并1,2两步)
以节点流为例:
读取文件
1.建立一个流对象,将已存在的一个文件加载进流。
- FileReader fr = new FileReader(new File(“Test.txt”));
2.创建一个临时存放数据的数组。
- char[] ch = new char[1024];
3.调用流对象的读取方法将流中的数据读入到数组中。
- fr.read(ch);
4. 关闭资源。
- fr.close();
写入文件
1.创建流对象,建立数据存放文件
- FileWriter fw = new FileWriter(new File(“Test.txt”));
2.调用流对象的写入方法,将数据写入流
- fw.write(“text.txt”);
3.关闭流资源,并将流中的数据清空到文件中。
- fw.close();
注意:
- 在写入一个文件时,如果使用构造器FileOutputStream(file),则目录下有同名文件将被覆盖。
- 如果使用构造器FileOutputStream(file,true),则目录下的同名文件不会被覆盖,在文件内容末尾追加内容。
- 在读取文件时,必须保证该文件已存在,否则报异常。
- 字节流操作字节,比如: .mp3, .avi, .rmvb, mp4, .jpg, .doc, .ppt
- 字符流操作字符,只能操作普通文本文件。 最常见的文本文件: .txt, .java, .c, .cpp
等语言的源代码。尤其注意.doc,excel,ppt这些不是文本文件
package com.itany.io;
import org.junit.Test;
import java.io.*;
/**
* Author: zhh
* Date: 2022-10-09 18:31
* Description: 节点流的使用
*/
public class Test01 {
@Test
public void test() {
FileReader fr=null;
try{
//1、实例化File类的对象,说明要操作的文件
File file = new File("src\\com\\itany\\hello.txt");
// System.out.println(file.getAbsolutePath());
//2、提供具体的流
fr = new FileReader(file);
//3、数据的读入
//read()返回读入的一个字符,如果到达文件末尾,返回-1
// int data=fr.read();
// while(data!=-1){
// System.out.print((char) data);
// data=fr.read();
// }
int data;
while((data=fr.read())!=-1){
System.out.print((char) data);
}
}catch(IOException e){
e.printStackTrace();
}finally {
//4、流的关闭
try {
if (fr != null) {
fr.close();
}
} catch(IOException e){
e.printStackTrace();
}
}
}
@Test
public void test01(){
FileReader fr=null;
File file = new File("src\\com\\itany\\hello.txt");
try {
fr = new FileReader(file);
char[] buf=new char[5];
int len;
while((len=fr.read(buf)) != -1){
// for(int i=0;i<len;i++){
// System.out.print(buf[i]);
// }
String str=new String(buf,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testWrite(){
File file = new File("testWrite.txt");
FileWriter fw =null;
try {
fw = new FileWriter(file,true);
//写true原文件存在就在原文件的后面追加,
// 不写默认false,原文件存在则覆盖,不存在都会创建
fw.write("hello\n");
fw.write("world");
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fw!= null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace ();
}
}
}
}
@Test
public void testReadAndWrite(){
FileReader fr= null;
FileWriter fw= null;
try {
File fileR=new File("src\\com\\itany\\hello.txt");
File fileW=new File("testWrite.txt");
fr = new FileReader(fileR);
fw = new FileWriter(fileW);
char[] buf=new char[5];
int len;
while ((len = fr.read(buf)) != -1){
fw.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fw != null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fr != null){
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testInputOutputStream(){
FileInputStream fis= null;
FileOutputStream fos= null;
try {
File fileIn=new File("src\\fish.jpg");
File fileOut=new File("outPic.jpg");
fis = new FileInputStream(fileIn);
fos = new FileOutputStream(fileOut);
byte[] buf=new byte[1024];
int len;
while((len=fis.read(buf))!= -1){
fos.write(buf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void copy(String src, String dest){
FileInputStream fis= null;
FileOutputStream fos= null;
try {
File fileIn=new File(src);
File fileOut=new File(dest);
fis = new FileInputStream(fileIn);
fos = new FileOutputStream(fileOut);
byte[] buf=new byte[1024];
int len;
while((len=fis.read(buf))!= -1){
fos.write(buf, 0, len);
}
System.out.println("复制成功");
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void testCopy(){
long begin = System.currentTimeMillis();
copy("outPic.jpg","copyPic.jpg");
long end = System.currentTimeMillis();
System.out.println("复制用时:"+(end-begin));
}
}
处理流之一:缓冲流
- 当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区
- 当使用BufferedInputStream读取字节文件时, BufferedInputStream会一次性从文件中读取8192个(8Kb), 存在缓冲区中, 直到缓冲区装满了,才重新从文件中读取下一个8192个字节数组。
- 向流中写入字节时, 不会直接写到文件, 先写到缓冲区中直到缓冲区写满,
- BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法flush()可以强制将缓冲区的内容全部写入输出流
- 关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可, 关闭最外层流也 会相应关闭内层节点流
- flush()方法的使用:手动将buffer中内容写入文件
- 如果是带缓冲区的流对象的close()方法, 不但会关闭流, 还会在关闭流之前刷 新缓冲区,关闭后不能再写出
package com.itany.io;
import org.junit.Test;
import java.io.*;
/**
* Author: zhh
* Date: 2022-10-09 23:17
* Description:缓冲流的使用
*/
public class BufferedTest {
@Test
public void BufferedTest01() {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
File fileIn = new File("outPic.jpg");
File fileOut = new File("outPicX.jpg");
FileInputStream fis = new FileInputStream(fileIn);
bis = new BufferedInputStream(fis);
FileOutputStream fos=new FileOutputStream(fileOut);
bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer))!= -1) {
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流时,先关闭外层的流,再关闭内层的流
//优化过:外层流关闭后内层流自动关闭
if(bos!=null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis!=null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void BufferedTest02(){
BufferedReader br = null;
BufferedWriter bw= null;
try {
br = new BufferedReader(new FileReader(new File("src\\com\\itany\\hello.txt")));
bw = new BufferedWriter(new FileWriter(new File("BufferedWriterOut.txt")));//输出的缓冲流包含flush()
//方式一
// char[] buf = new char[1024];
// int len;
// while((len=br.read(buf))!=-1){
// bw.write(buf, 0, len);
// }
//方式二
String data;
while((data=br.readLine())!=null){//data中不包含换行符
//方法一
// bw.write(data+"\n");
//方法二
bw.write(data);
bw.newLine();//提供换行
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (br!=null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
转换流
- 转换流提供了在字节流和字符流之间的转换
- Java API提供了两个转换流:
InputStreamReader:将InputStream转换为Reader
OutputStreamWriter:将Writer转换为OutputStream - 很多时候我们使用转换流来处理文件乱码问题。实现编码和 解
InputStreamReader
- 实现将字节的输入流按指定字符集转换为字符的输入流。
- 构造器
public InputStreamReader(InputStream in)
public InputSreamReader(InputStream in,String charsetName)
第二个参数用来指定字符集
OutputStreamWriter
- 实现将字符的输出流按指定字符集转换为字节的输出流
- 构造器
public OutputStreamWriter(OutputStream out)
public OutputSreamWriter(OutputStream out,String charsetName)
package com.itany.io;
import org.junit.Test;
import java.io.*;
/**
* Author: zhh
* Date: 2022-10-11 18:02
* Description: 转换流
*/
public class ConvertStream {
@Test
public void test1() {
InputStreamReader isr = null;
try {
FileInputStream fis = new FileInputStream("src\\com\\itany\\hello.txt");
isr = new InputStreamReader(fis,"UTF-8");
//具体使用哪个字符集取决于hello.txt保存时所使用的字符集
//isr = new InputStreamReader(fis);//第二个参数不写就使用默认的
char[] buf = new char[1024];
int len;
while ((len = isr.read(buf)) != -1) {
String str = new String(buf,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (isr != null){
try {
isr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2(){
InputStreamReader isr = null;
OutputStreamWriter osw= null;
try {
File file1 = new File("src\\com\\itany\\hello.txt");
File file2 = new File("hello_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
isr = new InputStreamReader(fis,"utf-8");
osw = new OutputStreamWriter(fos,"gbk");
char[] buf = new char[1024];
int len ;
while((len = isr.read(buf)) != -1){
osw.write(buf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(osw != null){
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(isr != null){
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
对象流
- ObjectInputStream和OjbectOutputSteam
- 用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
- 序列化: 用ObjectOutputStream类保存基本类型数据或对象的机制
- 反序列化: 用ObjectInputStream类读取基本类型数据或对象的机制
- ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量
- 序列化过程:将内存中的Java对象保存到磁盘中或通过网络传输出去,使用ObjectOutputStream
- 反系列化过程:将磁盘中的对象还原成内存中的对象,使用ObjectInputStream
- 这两个流不能序列化static和transient修饰的成员属性
自定义类需要满足哪些条件才能序列化?
- 需要实现接口:Serializable
- 当前类提供一个全局常量:serialVersionUID
- 除了当前类需要实现Serializable接口之外,还必须保证其内部所有的属性也必须是可序列化的(默认情况下,基本数据类型课序列化。)
序列化之后再反序列化之前更改序列号,然后再反序列化会报错
package com.itany.io;
import java.io.Serializable;
/**
* Author: zhh
* Date: 2022-10-16 19:49
* Description: <描述>
*/
public class Person implements Serializable {
private static final long serialVersionUID = 2L;
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Person{name = " + name + ", age = " + age + "}";
}
}
package com.itany.io;
import org.junit.Test;
import java.io.*;
/**
* Author: zhh
* Date: 2022-10-16 18:55
* Description: 序列化
*/
public class ObjectTest {
@Test
public void testObjectOutputStream(){
ObjectOutputStream oos= null;
try {
oos = new ObjectOutputStream(new FileOutputStream("text.dat"));
oos.writeObject(new String("恭喜20大的召开"));
oos.flush();//刷新操作
oos.writeObject(new Person("zhh",22));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//反系列化:将磁盘中的对象还原成内存中的对象
@Test
public void testObjectInputStream(){
ObjectInputStream ois= null;
try {
ois = new ObjectInputStream(new FileInputStream("text.dat"));
String obj=(String)ois.readObject();
System.out.println(obj);
Person person =(Person)ois.readObject();
System.out.println(person);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}