JavaIO流
File
1.概念
存储数据的方案:变量、数组、对象、集合,他们都是内存中的数据,在断电或者程序终止时会丢失;文件是保存数据的地方,在计算机硬盘中,即使断电或者程序终止,存储在硬盘的数据不会丢失,可以长久保存数据。
File类只能对文件本身进行操作,不能读写文件里面存储的数据
IO流:用于读写数据(可以读写文件、网络中的数据)
- 文件流:文件在程序中是以流的形式来操作的
- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据在数据源(文件)到程序(内存)的路径
- 输出流:数据从程序(内存)到数据源(文件)的路径
2.常用操作
- 创建文件对象
构造器 | 说明 |
---|---|
File(String pathname) | 根据路径构造一个File对象 |
File(File parent,String child) | 根据父目录文件+子路径构建 |
File(String parent,String child) | 根据父目录+子路径构建 |
方法:public boolean createNewFile() 创建新文件
import java.io.File;
import java.io.IOException;
public class FileCreat {
public static void main(String[] args) {
//方式一
String filePath1 = "d:/news1.txt";
File file1 = new File(filePath1);
try {
file1.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
//方式二
File parentfile2 = new File("d:\\");
String filePath2 = "news2.txt";
File file2 = new File(parentfile2,filePath2);
try {
file2.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
//方式三
String parentPath3 = "d:\\";
String filePath3 = "news3.txt";
File file3 = new File(parentPath3,filePath3);
try {
file3.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 获取文件信息
方法名称 | 说明 |
---|---|
public boolean exists() | 判断当前文件对象,对应的文件路径是否存在 |
public boolean isFile() | 判断当前文件对象指代的是否是文件 |
public boolean isDirectory() | 判断当前文件对象指代的是否是文件夹 |
public String getName() | 获取文件的名称(包含后缀) |
public long length() | 获取文件的大小,返回字节个数 |
public long lastModified() | 获取文件的最后修改时间 |
public String getPath() | 获取创建文件对象时使用的路径 |
public String getAbsolutePath() | 获取绝对路径 |
public String getParent() | 获取文件父级目录 |
import java.io.File;
import java.text.SimpleDateFormat;
public class FileInformation {
public static void main(String[] args) {
File file = new File("d:\\news1.txt");
System.out.println("文件名字="+file.getName());//文件名字=news1.txt
System.out.println("创建文件对象时,使用的路径="+file.getPath());//创建文件对象时,使用的路径=d:\news1.txt
System.out.println("文件绝对路径="+file.getAbsolutePath());//文件绝对路径=d:\news1.txt
System.out.println("文件父级目录="+file.getParent());//文件父级目录=d:\
System.out.println("文件大小(字节)="+file.length());//文件大小(字节)=11
System.out.println("文件是否存在="+file.exists());//文件是否存在=true
System.out.println("是不是一个文件="+file.isFile());//是不是一个文件=true
System.out.println("是不是一个目录="+file.isDirectory());//是不是一个目录=false
long time = file.lastModified();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println("最后修改时间="+sdf.format(time));//最后修改时间=2024/04/04 08:19:59
}
}
- 目录的操作和文件删除
方法名称 | 说明 |
---|---|
public boolean mkdir() | 只能创建一级文件夹 |
public boolean mkdirs() | 可以创建多级文件夹 |
public boolean delete() | 删除文件、空文件夹 |
import java.io.File;
public class Directory {
public static void main(String[] args) {
//创建一级文件
File file1 = new File("d:\\demo");
System.out.println(file1.mkdir());//true
//创建多级文件
File file2 = new File("d:\\demo\\a\\b\\c");
System.out.println(file2.mkdirs());//true
//删除文件
File file3 = new File("d:\\news1.txt");
System.out.println(file3.delete());//true
//删除空文件夹
System.out.println(file2.delete());//true
}
}
- 遍历文件夹
方法名称 | 说明 |
---|---|
public String[ ] list() | 获取当前目录下的所有“一级文件名称”到一个字符串数组中去返回 |
public File[ ] listFiles() | 获取当前目录下的所有“一级文件对象”到一个文件对象数组中去返回 |
import java.io.File;
public class FileTest1 {
public static void main(String[] args) {
File f1 = new File("D:\\demo");
String[] names = f1.list();
for (String name : names){
System.out.print(name);
}
File[] files = f1.listFiles();
for(File file:files){
System.out.print(file.getAbsoluteFile());
}
}
}
使用listFiles方法时的注意事项:
- 当主调是文件或路径不存在时,返回null
- 当主调是空文件夹时,返回一个长度为0的数组:[ ]
- 当主调是一个有内容的文件夹时,将里面所有一级文件和文件夹的路径放在File数组中返回
- 当主调是一个文件夹,且里面有隐藏文件时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏文件
- 当主调是一个文件夹,但是没有权限访问该文件夹时,返回null
(找多级文件,实现文件搜索,需要运用方法递归)
Path
Java.nio.file.Path接口类似于Java.io.File类,许多情况下,可以使用Path接口替换File类的使用
使用Path类进行路径中文件名的获取
- 创建Path对象:Path.get()
import java.nio.file.Path;
import java.nio.file.Paths;
public class PathDemo {
public static void main(String[] args) {
//使用绝对路径创建
Path absolutePath = Paths.get("E:\\Java\\myio\\a.txt");
//使用相对路径创建
Path relativePath = Paths.get("E:\\Java\\myio","a.txt");
System.out.println(absolutePath.equals(relativePath));//ture
}
}
- Paths类方法
方法 | 描述 |
---|---|
static Path get(String first,String …) | 根据给定的路径字符串和更多路径字符串创建Path对象,允许使用多个字符串片段来构建路径 |
static Path (URI uri) | 根据给定的URI创建Path对象 |
static Path get(Path path) | 根据给定的Path对象创建新的Path对象 |
- Path接口方法
方法 | 描述 |
---|---|
Path getFileName() | 返回路径中的文件名部分 |
Path getParent() | 返回路径中的父路径 |
Path resolve(String other) | 解析给定的路径字符串,并返回一个新的Path对象,该对象表示将当前路径与给定路径合并后的结果 |
Path normalize() | 返回规范化的路径,去除多余的目录分隔符、'.‘和’…'等元素 |
Path toAbsolutePath() | 返回当前路径的绝对路径 |
IO流原理及流的分类
1.Java IO流原理
- 用于处理数据传输,如读写文件、网络通讯等。
- Java程序中,对于数据的输入输出操作以流的方式进行
- java.io包下提供了各种流类和接口,用于获取不同种类的数据,并通过方法输入或输出数据
- 输入input:读取外部数据(磁盘、光盘、数据库、网络等存储设备的数据)到程序(内存)中
- 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中
2.流的分类
- 按操作数据单位:字节流(8 bit)(二进制文件)、字符流(按字符)(文本文件)
- 按数据流的流向:输入流、输出流
- 按流的角色:节点流,处理流/包装流
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
字节流
1.FileInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来
步骤:
- 创建字节输入流对象:如果文件不存在,报错
- 读数据:一次读一个字节,读出来的是数据在ASCII上对应的数字;读到文件末尾,read方法返回-1;读取一次数据read()移动一次指针。
- 释放资源:每次使用完流之后都要释放资源
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fis = new FileInputStream("E:\\Java\\myio\\a.txt");
//2.循环读取
int b;
while((b=fis.read())!=-1){
System.out.println((char)b);
}
//3.释放资源
fis.close();
}
}
2. FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
步骤:
- 创建字节输出流对象:参数可以是字符串表示的路径或File对象;如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的;如果文件已经存在,则会清空文件。
- 写数据:write方法的参数是整数,但是实际上写到本地文件的是整数在ASCII上对应的字符
- 释放资源:每次使用完流之后都要释放资源
FileOutputStream写数据的三种方式
方法名称 | 说明 |
---|---|
void write(int b) | 一次写一个字节数据 |
void write(byte[ ] b) | 一次写一个字节数组数据 |
void write(byte[ ] b,int off,int len) | 一次写一个字节数组的部分数据 |
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//1. 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\Java\\myio\\a.txt");
// 2. 写数据
//方式一
fos.write(97);
//方式二
byte[] bytes={97,98,99,100};
fos.write(bytes);
//方式三
fos.write(bytes,0,3);
//3. 释放资源
fos.close();
}
}
a.txt :aabcdabc
换行和续写
换行:windows \r\n或\r或\n
续写:创建对象的第二个参数默认false,表示关闭续写,创建对象会清空文件;手动传递true,表示打开续写,创建对象不会清空文件。
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//1. 创建字节输出流对象
FileOutputStream fos = new FileOutputStream("E:\\Java\\myio\\a.txt",true);
// 2. 写数据
String str1 = "\r\n";
byte[] bytes1 = str1.getBytes();
fos.write(bytes1);
String str2 = "666";
byte[] bytes2 = str2.getBytes();
fos.write(bytes2);
//3. 释放资源
fos.close();
}
}
aabcdabc
666
3.文件拷贝
方法名称 | 说明 |
---|---|
public int read() | 一次读一个字节数据 |
public int read(byte[ ] buffer) | 一次读一个字节数组数据,每次读取尽可能把数组装满,长度用1024的整数倍 |
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo1 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fis = new FileInputStream("E:\\Java\\myio\\a.txt");
FileOutputStream fos1 = new FileOutputStream("E:\\Java\\myio\\b.txt");
FileOutputStream fos2 = new FileOutputStream("E:\\Java\\myio\\c.txt");
//2.拷贝:边读边写
//方法一:一次读一个字节数据
//int b;
//while((b= fis.read())!=-1){
// fos1.write(b);
//}
//方法二:一次读一个字节数组数据
int len;
byte[] bytes = new byte[1024];
while ((len=fis.read(bytes))!=-1){
System.out.println("len");
fos2.write(bytes,0,len);
}
//3.释放资源,先开的最后关闭
fos2.close();
// fos1.close();
fis.close();
}
}
字符流
1.字符集
- ASCII字符集:英文用一个字节存储
- GBK字符集:Windows系统默认使用GBK,系统显示ANSI;
英文用一个字节存储,兼容ASCII,前面补0,二进制以0开头;
汉字用两个字节存储,高位字节二进制以1开头,转成十进制为负数 - Unicode字符集:国际标准字符集,将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息交换;
UTF-8编码规则:用1-4个字节保存;
英文字母用一个字节表示,二进制第一位补0;
中文汉字用三个字节表示(1110xxxx 10xxxxxx 10xxxxxx)
乱码出现原因:
1.字节流读取文本文件:一次读取一个字节(字节流读取中文会乱码,拷贝不会乱码)
2.编码和解码方式不统一
编码和解码的方法
String类中的方法 | 说明 |
---|---|
public byte[ ] getBytes() | 使用默认方式进行编码 |
public byte[ ] getBytes(String charsetName) | 使用指定方式进行编码 |
String (byte[ ] bytes) | 使用默认方式进行解码 |
String (byte[ ] bytes,String charsetName) | 使用指定方式进行解码 |
字符流=字节流+字符集
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码方式进行编码,变成字节再写到文件中
2.FileReader
- 创建字符输入流对象
底层:关联文件,并创建缓冲区(长度为8192的字节数组)
构造方法 | 说明 |
---|---|
public FileReader(File file) | 创建字符输入流关联本地文件 |
public FileReader(String pathname) | 创建字符输入流关联本地文件 |
- 读数据
底层:判断缓冲区中是否有数据可以读取;
若缓冲区没有数据,从文件获取数据到缓冲区;
若缓冲区有数据,就从缓冲区读取。
成员方法 | 说明 |
---|---|
public int read() | 读取数据,读到末尾返回-1,读取数据之后,进行解码转化为十进制作为返回值,若想看到中文汉字需要进行强转。 |
public int read(char[] buffer ) | 读取多个数据,读到末尾返回-1,读取数据、解码、强转、将强转之后的字符放到数组中 |
- 释放资源
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("E:\\Java\\myio\\a.txt");
//空参read方法public int read()
//int ch;
//while((ch = fr.read())!=-1){
// System.out.print((char)ch);
//}
//public int read(char[] buffer )
char[] chars = new char[2];
int len;
while ((len=fr.read(chars))!=-1){
System.out.print(new String(chars,0,len));
}
fr.close();
}
}
3.FileWriter
- 创建字符输出流对象
构造方法 | 说明 |
---|---|
public FileWriter(File file) | 创建字符输出流关联本地文件 |
public FileWriter(String pathname) | 创建字符输出流关联本地文件 |
public FileWriter(File file,boolean append) | 创建字符输出流关联本地文件,续写 |
public FileWriter(String pathname,boolean append) | 创建字符输出流关联本地文件,续写 |
- 写数据
成员方法 | 说明 |
---|---|
void write(int c) | 写出一个字符 |
void write(String str) | 写出一个字符串 |
void write(String str,int off,int len) | 写出一个字符串的一部分 |
void write(char[] cbuf) | 写出一个字符数组 |
void write(char[] cbuf,int off,int len) | 写出字符数组的一部分 |
- 释放资源
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("E:\\Java\\myio\\a.txt",true);
fw.write(25105);
fw.write("你好你好",0,2);
char[] chars = {'a','b','c','d'};
fw.write(chars,0,2);
fw.close();
}
}
缓冲流
底层自带了长度为8192的缓冲区提高性能
字节缓冲流缓冲区为byte型,长度是8KB
字符缓冲流缓冲区为char型,长度是16KB
1.字节缓冲流
可以显著提高字节流的读写性能
方法名称 | 说明 |
---|---|
public BufferedInputStream(InputStream is) | 把基本流包装成高级流,提高读取数据的性能 |
public BufferedOutputStream(OutputStream os) | 把基本流包装成高级流,提高写出数据的性能 |
import java.io.*;
public class BufferedStreamDemo1 {
public static void main(String[] args) throws IOException {
//利用字节缓冲流拷贝文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Java\\myio\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\Java\\myio\\b.txt"));
int b;
while((b= bis.read())!=-1){
bos.write(b);
}
bos.close();
bis.close();
}
2.字符缓冲流
对字符流提升不明显,关键是两个特有的方法
方法名称 | 说明 |
---|---|
public BufferedReader(Reader r) | 把基本流包装成高级流 |
public BufferedWriter(Writer r) | 把基本流包装成高级流 |
public String readLine() | 读取一行数据,如果没有数据可读,返回null |
public void newLine() | 跨平台的换行 |
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BufferedStreamDemo2 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("e:\\java\\myio\\a.txt"));
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
br.close();
}
}
import java.io.*;
public class BufferedStreamDemo3 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("e:\\java\\myio\\b.txt"));
bw.write("abc");
bw.newLine();
bw.write("def");
bw.close();
}
}
转换流
是字符流与字节流之间的桥梁,使字节流可以使用字符流中的方法
1.InputStreamReader
构造方法 | 说明 |
---|---|
InputStreamReader(InputStream in) | 创建一个使用默认字符集的字符流 |
InputStreamReader(InputStream in,String charsetName) | 创建一个使用指定字符集的字符流 |
2. OutputStreamWriter
构造方法 | 说明 |
---|---|
OutputStreamWriter (OutputStream in) | 创建一个使用默认字符集的字符流 |
OutputStreamWriter (OutputStream in,String charsetName) | 创建一个使用指定字符集的字符流 |
对象流
序列化流、反序列化流
1.ObjectOutputStream
序列化流(对象操作输出流)
构造方法 | 说明 |
---|---|
public ObjectOutputStream(OutputStream out) | 把基本流包装成高级流 |
成员方法 | 说明 |
---|---|
public final void writeObject(Object obj) | 把对象序列化到文件中去 |
import java.io.Serializable;
public class Student implements Serializable {
//
private static final long serialVersionUID = -427553587245757343L;
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
Student stu = new Student("zhangsan",22);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\Java\\myio\\a.txt"));
oos.writeObject(stu);
oos.close();
}
}
2. ObjectInputStream
反序列化流(对象操作输入流)
构造方法 | 说明 |
---|---|
public ObjectInputStream(InputStream in) | 把基本流包装成高级流 |
成员方法 | 说明 |
---|---|
public Object readObject() | 把序列化到本地文件中的对象,读取到程序中来 |
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\Java\\myio\\a.txt"));
Object o = ois.readObject();
System.out.println(o);
ois.close();
}
}
- Serializable接口里面没有抽象方法,标记型接口,一旦实现了这个接口,那么就表示当前的类可以被序列化
- 序列化写到文件中的数据不能被修改,否则无法再次读回来
- 序列化对象后,修改了Javabean类,再次反序列化,会抛出异常,需要给Javabean类添加serialVersionUID(序列号、版本号)(先写标准Javabean,最后写serialVersionUID)
- transient关键字标记的成员变量不参与序列化过程,读取时默认初始化值
打印流
1. PrintStream
字节打印流
构造方法 | 说明 |
---|---|
public PrintStream(OutputStream/File/String) | 关联字节输出流/文件/文件路径 |
public PrintStream(String fileName,Charset charset) | 指定字符编码 |
成员方法 | 说明 |
---|---|
public void println(Xxx xx) | 打印任意数据,自动刷新,自动换行 |
public void print(Xxx xx) | 打印任意数据,不换行 |
public void printf(String format, Object… args) | 带有占位符的打印语句,不换行 |
2.PrintWriter
字符打印流,字符流底层有缓冲区想要自动刷新需要开启
构造方法 | 说明 |
---|---|
public PrintWriter(Write/File/String) | 关联字节输出流/文件/文件路径 |
public PrintWriter(String fileName,Charset charset) | 指定字符编码 |
public PrintWriter(Write w,boolean autoFlush) | 自动刷新 |
public PrintWriter(OutputStream out,boolean autoFlush,Charset charset) | 指定字符编码且自动刷新 |
成员方法与字节打印流类似
数据流
- 数据输入流:DataInputStream
- 数据输出流:DataOutputStream
允许程序按着机器无关的风格读取Java原始数据,不必关心数据有多少字节
方法名称 | 说明 |
---|---|
DataInputStream(InputStream is) | 创建的数据输入流指向一个由参数in指定的底层输入流 |
DataOutputStream(OutputStream out) | 创建的数据输出流指向一个由参数out指定的底层输入流 |
常用方法:readBoolean(),readByte(),readChar(),readDouble(),readBFloat(),readInt(),readLong(),readShort(),readUnsignedByte(),readUnsignedShort(),readUTF()读取一个UTF字符串,skipBytes(int n)跳过给定数量的字节
writeBoolean(boolean v),writeBytes(String s),writeChars(String s),writeDouble(double v),writeFloat(float v),writeInt(int v),writeLong(long v),writeShort(int v),writeUTF(String s)
import java.io.*;
public class DataStream {
public static void main(String[] args) throws IOException {
File file = new File("E:\\Java\\myio\\a.txt");
DataOutputStream dos = new DataOutputStream(new FileOutputStream(file));
dos.writeInt(100);
dos.writeBoolean(true);
dos.writeChars("abcdefabcdef");
DataInputStream dis = new DataInputStream(new FileInputStream(file));
System.out.println(dis.readInt());
System.out.println(dis.readBoolean());
dis.close();
dos.close();
}
}