前言
java - IO流系列文章:
本文意在整理所有流相关的代码。便于复习和快速参考,
强力推荐文章:Java的IO流总结
文章目录
一、File 文件类
java.io.File类:文件和目录路径名的抽象表示形式,与平台无关。File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。File对象可以作为参数传递给流的构造函数。
1.1、File类常用方法
1.2、示例
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.Date;
/*
* java.io.File类
* 1.凡是与输入、输出相关的类、接口等都定义在java.io包下
* 2.File是一个类,可以有构造器创建其对象。此对象对应着一个文件(.txt .avi .doc .ppt .mp3 .jpg)或文件目录
* 3.File类对象是与平台无关的。
* 4.File中的方法,仅涉及到如何创建、删除、重命名等等。只要涉及文件内容的,File是无能为力的,必须由io流来完成。
* 5.File类的对象常作为io流的具体类的构造器的形参。
*/
public class TestFile {
/*
* 路径:
* 绝对路径:包括盘符在内的完整的文件路径
* 相对路径:在当前文件目录下的文件的路径
*
* getName()
getPath()
getAbsoluteFile()
getAbsolutePath()
getParent()
renameTo(File newName)
*/
@Test
public void test1(){
File file1 = new File("D:/config.txt");
File file2 = new File("D:/co.txt");
System.out.println(file1.getName());
System.out.println(file1.getAbsoluteFile());
System.out.println(file1.getAbsolutePath());
System.out.println(file1.getPath());
System.out.println(file1.getParent());
System.out.println();
System.out.println(file2.getName());
System.out.println(file2.getAbsoluteFile());
System.out.println(file2.getAbsolutePath());
System.out.println(file2.getPath());
System.out.println(file2.getParent());
boolean b = file1.renameTo(file2);//要提供完整路径
System.out.println(b);
}
/**
* 文件检测
* exists()
* canWrite()
* canRead()
* isFile()
* isDirectory()
*/
@Test
public void test2(){
System.out.println(System.getProperty("user.dir"));//通过改行代码确定当前路径的相对位置。
File file = new File("src/IO/config.txt");//注意File的相对路径是相对于当前的user.dir来说的,
File dir = new File("src/IO/test");
System.out.println(file.exists());
System.out.println(file.canExecute());
System.out.println(file.canRead());
System.out.println(file.canWrite());
System.out.println(file.isDirectory());
System.out.println(new Date(file.lastModified()));
System.out.println(file.length());
System.out.println();
System.out.println(dir.exists());
System.out.println(dir.canExecute());
System.out.println(dir.canRead());
System.out.println(dir.canWrite());
System.out.println(dir.isDirectory());
System.out.println(new Date(dir.lastModified()));
System.out.println(dir.length());
}
/*
* createNewFile()
delete()
mkDir():创建一个文件目录。只有在上层文件目录存在的情况下,才能返回true
mkDirs():创建一个文件目录。若上层文件目录不存在,一并创建
list()
listFiles()
*/
@Test
public void test3() throws IOException {
File file1 = new File("src/IO/a.txt");
System.out.println(file1.createNewFile());//创建新的文件
File file2 = new File("src/IO/a");
file2.mkdir();//创建相对目录,如果成功返回true否则返回false,注意要保证上级目录存在
File file3 = new File("D:/TTT/TTT");
file3.mkdirs();//创建目录,如果上级目录不存在则一并创建。
File file4 = new File("src/IO");
File[] files = file4.listFiles();//返回目录下的文件列表
for (int i = 0; i < files.length; i++) {
System.out.println(files[i]);
}
}
// 判断文件E:\Java\Java学习笔记\IO流\news1.txt 是否存在,如存在就删除。如不存在,则创建
@Test
public void m1(){
String filePath = "E:\\Java\\Java学习笔记\\IO流\\news1.txt";
File file = new File(filePath);
if(file.exists()) {
if(file.delete())
System.out.println("news1.txt 被删除!");
else
System.out.println("文件删除失败!");
}else{
try {
file.createNewFile();
System.out.println("news1.txt 被创建!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
二、输入输出流
常见的IO流如下:
2.1、字节流
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestInputOutput {
/**
* 从硬盘读取一个文件,并写入到另一个位置。(相当于文件的复制)
*/
@Test
public void test(){
FileInputStream fis = null;
FileOutputStream fos = null;
long start = System.currentTimeMillis();
try(
fis = new FileInputStream(new File("a.jpg"));
fos = new FileOutputStream(new File("a1.jpg"));
//FileInputStream fis = new FileInputStream(srcPath);
//FileOutputStream fos = new FileOutputStream(destPath);
){
//数组的大小影响文件写出的效率,文件太小多次写入浪费时间,太大则浪费空间。
byte[] b = new byte[1024*8];
int len;
while ((len = fis.read(b))!=-1){
fos.write(b,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("时间共花了"+(end-start));
}
}
2.2、字符流
FileReader和FileWriter用来对文本文件进行读写(注意一般指txt文件,doc文件不是文本文件),其速度效率要快于字节流读取.
文本文件,对于非文本文件(视频文件、音频文件、图片),只能使用字节流!
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TestFileReaderWriter {
@Test
public void test() throws IOException {
FileReader fr = null;
FileWriter fw = null;
try (
fr = new FileReader(new File("src/IO/a.txt"));
fw =new FileWriter(new File("src/IO/bb.txt"));
){
char[] a = new char[8*1024];
int len;
while((len = fr.read(a))!=-1){
System.out.println(len);
System.out.println(new String(a,0,len));
fw.write(a,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.3、缓冲流
为了提高数据的读写速度,java API提供了带缓冲功能的流,根据数据类型,缓冲流分为
字节缓冲流和字符缓冲流。
2.3.1、字节缓冲流
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.*;
/*
* 抽象基类 节点流(文件流) 缓冲流(处理流的一种,可以提升文件操作的效率)
* InputStream FileInputStream BufferedInputStream
* OutputStream FileOutputStream BufferedOutputStream (flush())
* Reader FileReader BufferedReader (readLine())
* Writer FileWriter BufferedWriter (flush())
*/
public class TestBuffered {
/*
* 使用缓冲流加速字节流读取非文本文件的速度
*/
@Test
public void test() {
BufferedInputStream br = null;
BufferedOutputStream bw = null;
FileInputStream fis = null;
FileOutputStream fos = null;
long start = System.currentTimeMillis();
try (
fis = new FileInputStream(new File("a.jpg"));
fos = new FileOutputStream(new File("a3.jpg"));
br = new BufferedInputStream(fis);
bw = new BufferedOutputStream(fos);
){
//数组的大小影响文件写出的效率,文件太小多次写入浪费时间,太大则浪费空间。
byte[] b = new byte[1024];
int len;
while ((len = br.read(b)) != -1) {
bw.write(b, 0, len);
}
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("时间共花了" + (end - start));
}
}
2.3.2、字符缓冲流
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.*;
/*
* 使用缓冲流加速字节流读取非文本文件的速度
*/
@Test
public void test2() {
BufferedReader br = null;
BufferedWriter bw = null;
FileReader fr = null;
FileWriter fw = null;
try (
fr = new FileReader(new File("src/IO/a.txt"));
fw =new FileWriter(new File("src/IO/bb.txt"));
br = new BufferedReader(fr);
bw = new BufferedWriter(fw);
){
char[] a = new char[5];
int len;
while((len = br.read(a))!=-1){
System.out.println(len);
System.out.println(new String(a,0,len));
bw.write(a);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.4、转换流
转换流可以将字节流读取到的字节,按指定字符集解码成字符
代码如下(示例):
@Test
public void test() throws IOException {
try(
//解码,把字节数组变成字符流
InputStreamReader isr = new InputStreamReader(new FileInputStream(new File("src/IO/a.txt")));
//编码,把字符流变成字节数组
FileOutputStream fos = new FileOutputStream(new File("src/IO/bbb.txt"));
// 【指定字符集】
OutputStreamWriter osr = new OutputStreamWriter(fos ,"utf-8");
BufferedReader br = new BufferedReader(isr);
BufferedWriter bw = new BufferedWriter(osr);
){
int len;
char[] c = new char[8*1024];
while((len = br.read(c))!=-1){
bw.write(c,0,len);
bw.flush();
}
}catch(Exception ext){
}
}
2.5、数据流
数据流:用来处理基本数据类型、String、字节数组的数据
代码如下(示例):
@Test
public void test4() throws Exception {
DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream("data.txt"));
dataOutputStream.writeUTF("我爱你,而你不知道");
dataOutputStream.writeBoolean(true);
dataOutputStream.writeInt(12);
dataOutputStream.close();//会乱码,但是再次读的时候会恢复
DataInputStream dataInputStream = new DataInputStream(new FileInputStream(new File("data.txt")));
// byte[] b =new byte[10];
// int len;
// while((len = dataInputStream.read(b))!=-1){
// System.out.println(new String(b,0,len));
// }
System.out.println(dataInputStream.readUTF());
System.out.println(dataInputStream.readBoolean());
System.out.println(dataInputStream.readInt());
dataInputStream.close();
}
2.6、对象流
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.*;
public class TestObjectInputOutputStream {
/**
* 对象的序列化过程:将内存中的对象通过ObjectOutputStream转换为二进制流,存储在硬盘文件中
*/
@Test
public void test() throws IOException {
Person person = new Person("花花", 12, new Pet("哈哈"));
Person person1 = new Person("瓜瓜", 22, new Pet("大大"));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.txt"));
oos.writeObject(person);
oos.flush();
oos.writeObject(person1);
oos.flush();
oos.close();
}
/**
* 对象的反序列化过程:将硬盘中的文件通过ObjectInputStream转换为相应的对象
*/
@Test
public void test1() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"));
Person person = (Person) ois.readObject();
Person person1 = (Person) ois.readObject();
System.out.println(person);
System.out.println(person1);
}
}
/*
* 要实现序列化的类: 1.要求此类是可序列化的:实现Serializable接口
* 2.要求类的属性同样的要实现Serializable接口
* 3.提供一个版本号:private static final long serialVersionUID
* 4.使用static或transient修饰的属性,不可实现序列化
*/
class Person implements Serializable{
private static final long serialVersionUID = 23456789L;
String name;
Integer age;
Pet pet;
public Person(String name, Integer age,Pet pet) {
this.name = name;
this.age = age;
this.pet = pet;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", pet=" + pet +
'}';
}
}
class Pet implements Serializable{
String name;
public Pet(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
}
2.7、随机访问
代码如下(示例):
package IO;
import org.junit.Test;
import java.io.File;
import java.io.RandomAccessFile;
public class TestRandomAccessFile {
@Test//RandomAccessFile进行文件的读写
public void test1() throws Exception {
RandomAccessFile randomAccessFile = new RandomAccessFile(new File("src/IO/a.txt"),"r");
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("src/IO/aa.txt"),"rw");
int len;
byte[] b = new byte[10];
while ((len = randomAccessFile.read(b))!=-1){
randomAccessFile1.write(b,0,len);
}
randomAccessFile1.close();
randomAccessFile.close();
}
@Test//实际上是覆盖的效果
public void test2() throws Exception {
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("src/IO/aa.txt"),"rw");
randomAccessFile1.seek(4);
//在第四个字符出写入xy,实则是覆盖,注意汉字一个字占两个字符,如26个字符覆盖后abcdxyghijklmnopqrstuvwxyz
randomAccessFile1.write("xy".getBytes());
randomAccessFile1.close();
}
@Test//处理覆盖
public void test3() throws Exception {
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("src/IO/aa.txt"),"rw");
randomAccessFile1.seek(4);
String str = randomAccessFile1.readLine();//弊端是只能处理一行
randomAccessFile1.seek(4);//指针已经移动,需要调整
randomAccessFile1.write("xy".getBytes());
randomAccessFile1.write(str.getBytes());//拿出来在追加上
randomAccessFile1.close();//abcdxyefghijklmnopqrstuvwxyz
}
@Test//更通用
public void test4() throws Exception {
RandomAccessFile randomAccessFile1 = new RandomAccessFile(new File("src/IO/aa.txt"),"rw");
randomAccessFile1.seek(4);
byte[] b = new byte[10];
int len;
StringBuffer sb = new StringBuffer();
while((len = randomAccessFile1.read(b)) != -1){
sb.append(new String(b,0,len));
}
randomAccessFile1.seek(4);//指针已经移动,需要调整
randomAccessFile1.write("xy".getBytes());
randomAccessFile1.write(sb.toString().getBytes());//拿出来在追加上
randomAccessFile1.close();//abcdxyefghijklmnopqrstuvwxyz
}
}
2.8、 Properties类
代码如下(示例):
public static void main(String[] args) {
String filePath = "E:\\Java\\Java学习笔记\\IO流\\Dir\\mysql.properties";
// 使用 Properties 读取配置文件
// 1. 创建Properties对象
Properties properties = new Properties();
try {
// 2. 加载配置文件中的键值对
properties.load(new FileReader(filePath));
// 3.把键值对显示到控制台
properties.list(System.out);
// 4.根据key 获取对应的值
String dbName = properties.getProperty("dbName");
String userName = properties.getProperty("userName");
System.out.println("dbName=" + dbName);
System.out.println("userName=" + userName);
System.out.println("=========================");
// 1. 根据Properties 类修改/添加 键值对
properties.setProperty("ip","127.0.0.1");
properties.setProperty("dbName", "NewDbName");
// 2. 存储到文件中
properties.store(new FileWriter(filePath), null); // comments 注释/注解
// 把键值对显示到控制台
properties.load(new FileReader(filePath));
properties.list(System.out);
} catch (IOException e) {
throw new RuntimeException(e);
}
System.out.println();
}
2.9、字节数组流
字节数组流,可以很容易获取字节数组【baos.getByteArray()】,方便输入流转输出流。
代码如下(示例):
import java.io.*;
public class DataStream {
public static void main(String[] args) {
ByteArrayOutputStream baos=new ByteArrayOutputStream();//创建字节数组流,同时会在内存里面创建数组
DataOutputStream dos=new DataOutputStream(baos);//对字节数组流外封装成数据处理流
try {
dos.writeDouble(Math.random());//利用数据流里面的写入方法,写一个Double类型的随机数据
dos.writeBoolean(true);
//toByteArray()方法是创建一个新分配的字节数组。数组的大小和当前输出流的大小。这里指的是baos这个字节数组
ByteArrayInputStream bias=new ByteArrayInputStream(baos.toByteArray());
System.out.println(bias.available());
DataInputStream dis=new DataInputStream(bias);
System.out.println(dis.readDouble());
System.out.println(dis.readBoolean());
dos.close();
dis.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
三、 Apache IO包
常用的工具类是 FileUtils 和 IOUtils
四、 常见问题
4.1、 字符串转 byte[]
String str = "hello,world";
byte[] b = str.getBytes();
参考资料: