File类
File类只用于表示文件(目录)的信息(名称、大小等),不能用于文件内容的访问。
package file类;
import java.io.File;
import java.io.IOException;
public class FileDemo {
public static void main(String[] args) {
File file = new File("C:\\Users\\lenovo\\Desktop\\file.txt");
System.out.println(file.exists());
if(!file.exists()) {
//file.mkdir();//如果不存在,则创建目录,会创建路径中的所有目录
try {
file.createNewFile();//创建一个文件
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("文件已创建");
}
else {
file.delete();//如果文件存在则删除
System.out.println("文件已删除");
}
}
}
RandomAccessFile类
RandomAccessFile java提供的对文件内容的访问,既可以读文件,也可以写文件。
RandomAccessFile支持随机访问文件,可以访问文件的任意位置
(1) java文件模型
在硬盘上的文件是byte byte byte存储的,是数据的集合
(2) 打开文件
有两种模式"rw"(读写) “r”(只读)
RandomAccessFile raf = new RandomeAccessFile(file,“rw”)
文件指针,打开文件时指针在开头 pointer = 0;
(3) 写方法
raf.write(int)—>只写一个字节(后8位),同时指针指向下一个位置,准备再次写入
(4) 读方法
int b = raf.read()—>读一个字节
(5) 文件读写完成以后一定要关闭(Oracle官方说明)
package randomAcccessFile类;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
public class RafDemo {
public static void main(String[] args) throws IOException {
File file = new File("demo");
if (!file.exists()) {
file.mkdir();
}
File file1 = new File(file, "raf.dat");
if (!file1.exists()) {
file1.createNewFile();
}
RandomAccessFile raf = new RandomAccessFile(file1, "rw");
// 指针的位置
System.out.println(raf.getFilePointer());
raf.write('A');// 只写了一个字节(低8位)
System.out.println(raf.getFilePointer());
raf.write('B');
int i = 0x7fffffff;
// 用write方法每次只能写一个字节,如果要把i写进去,就要 写4次
raf.write(i >>> 24);// 高8位
raf.write(i >>> 16);
raf.write(i >>> 8);
raf.write(i);
System.out.println(raf.getFilePointer());
// 可以直接写一个int
raf.writeInt(i);
String s = "中";
byte[] b = s.getBytes("GBK");
raf.write(b);
System.out.println(raf.length());
//读文件:必须把指针移到头部
raf.seek(0);
//一次性读取,把文件中的内容都读取到字节数组中
byte[] buf = new byte[(int)raf.length()];
raf.read(buf);
System.out.println(Arrays.toString(buf));
//将字节数组构造成字符串输出
String str = new String(buf,"GBK");
System.out.println(str);
System.out.println(Arrays.toString(buf));
raf.close();
}
}
字节流
-
InputStream、OutputStream
InputStream抽象了应用程序读取数据的方式
OutputStream抽象了应用程序写出数据的方式 -
EOF = End 读到-1就读到结尾
-
输入流基本方法
int b = in.read();读取一个字节无符号填充到int低八位.-1是 EOF
in.read(byte[] buf)
in.read(byte[] buf,int start,int size) -
输出流基本方法
out.write(int b) 写出一个byte到流,b的低8位
out.write(byte[] buf)将buf字节数组都写入到流
out.write(byte[] buf,int start,int size) -
FileInputStream—>具体实现了在文件上读取数据
-
FileOutputStream 实现了向文件中写出byte数据的方法
-
DataOutputStream/DataInputStream
对"流"功能的扩展,可以更加方面的读取int,long,字符等类型数据
DataOutputStream
writeInt()/writeDouble()/writeUTF() -
BufferedInputStream&BufferedOutputStream
这两个流类位IO提供了带缓冲区的操作,一般打开文件进行写入
或读取操作时,都会加上缓冲,这种流模式提高了IO的性能
从应用程序中把输入放入文件,相当于将一缸水倒入到另一个缸中:
FileOutputStream—>write()方法相当于一滴一滴地把水“转移”过去
DataOutputStream–>writeXxx()方法会方便一些,相当于一瓢一瓢把水“转移”过去
BufferedOutputStream—>write方法更方便,相当于一飘一瓢先放入桶中,再从桶中倒入到另一个缸中,性能提高了
package util;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
//字节流:按字节流读写不会出现乱码问题
public class IOUtil {
/**
* 以字节流读取指定文件的内容,按照16进制输出到控制台 并且每输出10个byte换行
*
* @param fileName
* @throws IOException
*/
public static void printHex(String filePath) throws IOException {
// 把文件作为字节流进行操作
FileInputStream in = new FileInputStream(filePath);
int b;
int i = 1;
while ((b = in.read()) != -1) {// 一次读取一个字节,8位
if (b <= 0xf) {
// 单位数前面补0
System.out.print("0");
}
System.out.print(b + "|");
System.out.print(Integer.toHexString(b));
}
in.close();
}
public static void printHexByByteArray(String filePath) throws IOException {
FileInputStream in = new FileInputStream(filePath);
byte[] buf = new byte[20 * 1024];
/*
* 从in中批量读取字节,放入到buf这个字节数组中 从第0个位置开始放,最多放buf.length个 返回的是读到的字节的个数
*/
/*
* int byteCounts = in.read(buf,0,buf.length);//一次性读完,说明字节数组足够大
*
* int j; for(int i = 0;i<byteCounts;i++) { if(buf[i] <= 0xf) {
* System.out.print("0"); } System.out.print(Integer.toHexString(buf[i])+" ");
* System.out.println(); }
*/
// 当不知byte数组是否足够大时:多次利用byte数组存放数据
int bytes = 0;
while ((bytes = in.read(buf, 0, buf.length)) != -1) {
for (int i = 0; i < bytes; i++) {
if (buf[i] <= 0xf) {
System.out.print("0");
}
System.out.print(Integer.toHexString(buf[i] & 0xff) + " ");
System.out.println();
}
}
}
/**
* 拷贝文件:字节批量读取:最快
*
* @param srcFile
* @param obFile
* @throws FileNotFoundException
*/
public static void copyFile(File srcFile, File obFile) throws Exception {
// 读取srcFile文件中的内容
FileInputStream in = new FileInputStream(srcFile);
// 向obFile写入内容
FileOutputStream out = new FileOutputStream(obFile);
byte[] buf = new byte[2 * 1024];
int b = 0;
while ((b = in.read(buf, 0, buf.length)) != -1) {// 读取文件中的内容
// 写入
out.write(buf, 0, b);
}
in.close();
out.close();
}
/**
* 单字节带缓冲的文件拷贝
*
* @param srcFile
* @param objFile
* @throws FileNotFoundException
*/
public static void copyFileByBuff(File srcFile, File objFile) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(objFile));
int c;
while ((c = bis.read()) != -1) {
bos.write(c);
//System.out.println(c);
}
bos.flush();// 刷新缓冲区
bis.close();
bos.close();
}
/**
* 单字节,不带缓冲进行文件拷贝:最慢
*
* @param srcFile
* @param objFile
* @throws FileNotFoundException
*/
public static void copyByByteByte(File srcFile, File objFile) throws Exception {
FileInputStream in = new FileInputStream(srcFile);
FileOutputStream out = new FileOutputStream(objFile);
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
out.flush();
in.close();
out.close();
}
public static void read(File file) throws IOException {
//FileInputStream in = new FileInputStream(file);//按当前项目的编码读取
FileInputStream in = new FileInputStream(file);//按当前项目的编码读取
int readLength = 0;
byte[] byt = new byte[2*1024];
while((readLength = in.read(byt, 0,byt.length)) != -1) {
String str = new String(byt,0,readLength,"UTF-8");
System.out.println(str);
}
}
}
字符流
-
编码问题
-
认识文本和文本文件
java的文本(char)是16位无符号整数,是字符的unicode编码(双字节编码)
文件是byte byte byte …的数据序列
文本文件是文本(char)序列按照某种编码方案(utf-8,utf-16be,gbk)序列化为byte的存储结果 -
字符流(Reader Writer)---->操作的是文本文本文件
字符的处理,一次处理一个字符
字符的底层任然是基本的字节序列
字符流的基本实现:
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理FileReader/FileWriter
字符流的过滤器:
BufferedReader ---->readLine 一次读一行
BufferedWriter/PrintWriter ---->写一行
- InputStreamReader 和 OutputStreamWriter
package 字符流;//字符流的操作的对象是文本,文本文件,默认按GBK编码解析:*操作时要以文件所在的编码进行读写*。
//字符流需要用字节流来构造
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import org.junit.Test;
/*InputStreamReader(将字节流转为字符流读出)和 OutputStreamWriter(将字符流转为字节流写入)
* FileReader继承了InputStreamReader,在new对象时不用再new一个InputStream,直接给文件
*/
public class IsrAndOsw {
@Test
public void test() throws IOException {
File file = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\11.txt");
//Reader isr = new FileReader(file);//不能指定编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(file),"UTF-8");//默认项目的编码,要写文件本身的编码
File fileout = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt");
OutputStreamWriter outw = new OutputStreamWriter(new FileOutputStream(fileout),"UTF-8");//以该文件所在的编码写入
// //方法一:
// int c;
// while((c = isr.read()) != -1) {
// System.out.print((char)c);
// }
//方法二:
char[] ch = new char[1*1024];
int charCounts = 0;
//返回的是读取到的字符的个数
while((charCounts = isr.read(ch, 0, ch.length)) != -1) {
String str = new String(ch,0,charCounts);
outw.write(ch,0,charCounts);
System.out.print(str);
}
outw.flush();
outw.close();
}
}
- FileReader和FileWriter
package 字符流;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.junit.Test;
/*
* FileReader和FileWriter:
* (1)在构造时不需要像InputStreamReader和OutputStreamWriter
* 再构造一个InputStream和OutputStream对象,已封装。
* (2)在构造时不能指定读和写的编码格式,所以在项目编码和文件编码不一致时会产生乱码
*
*/
public class FrAndFw {
@Test
public void test() throws IOException {
File filein = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\11.txt");
FileReader reader = new FileReader(filein);//不能指定读取的编码格式
File fileout = new File("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt");
FileWriter writer = new FileWriter(fileout);//可以追加
//FileWriter writer = new FileWriter(fileout,true);
int length;
char[] ch = new char[1*1204];
while((length = reader.read(ch,0,ch.length)) != -1) {
writer.write(ch, 0, length);
}
writer.flush();
writer.close();
reader.close();
}
}
- BufferedReader、BufferedWriter以及PrintWriter
package 字符流;
import java.io.*;
import org.junit.Test;
/*
* BufferedReader(线程安全)和BufferedWriter(线程安全)以及PrintWriter(线程安全)
* (1)PrintWriter对BufferedWriter的构造做了简化,在内部封装了,
* 但是这样就不能自己指定编码格式了,对于文件编码和项目编码格式不一样的情况下
* 会出现乱码。
*/
public class BrAndBwOrPw {
@Test
public void test() throws IOException {
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new FileInputStream("D:\\就职学习\\Java\\Java基础\\测试\\src\\11.txt"),"UTF-8"));
// BufferedWriter writer = new BufferedWriter(
// new OutputStreamWriter(
// new FileOutputStream("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt"),"UTF-8"));
PrintWriter pw = new PrintWriter(new FileOutputStream("D:\\就职学习\\Java\\Java基础\\测试\\src\\12.txt"));//会乱码
String str;
while((str = reader.readLine()) != null) {
System.out.println(str);
// writer.write(str);
// writer.newLine();//单独写入换行操作
pw.println(str);
}
reader.close();
// writer.flush();
// writer.close();
pw.flush();
pw.close();
}
}
对象的序列化和反序列化
-
对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化
-
序列化流(ObjectOutputStream),是过滤流----writeObject
反序列化流(ObjectInputStream)—readObject -
序列化接口(Serializable)
对象必须实现序列化接口 ,才能进行序列化,否则将出现异常
这个接口,没有任何方法,只是一个标准 -
transient关键字
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException分析ArrayList源码中序列化和反序列化的问题
-
序列化中子类和父类构造函数的调用问题
package 对象序列化和反序列化;
import java.io.Serializable;
/*对象的序列化和反序列化:
* (0)概念:将Object转换成byte序列为对象的序列化,反之称为反序列化。
* (1)要实现对象的序列化和反序列化首先类需要实现Serializable接口,这个接口是空的
* (2)通过 ObjectOuputStream对象oos.writeObject(object);对对象进行序列化
* 通过ObjectInputStream对象Student stu = (Student)ois.readObject();进行对象的反序列化
* (3)transien关键字:用transien关键字修饰的属性不会被jvm默认的序列化及反序列化(类成员变量都有默认值),
* 但是可以自己定义完成这个元素的序列化以及反序列化:
* //序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化
s.writeInt(stuage);//自己完成suage的序列化
}
//反序列化
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
this.stuage = s.readInt();//自己完成stuage的反序列化
}
(4)在序列化过程中,如果被序列化的类中定义了writeObject 和 readObject 方法,
虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义
的序列化和反序列化。 如果没有这样的方法,则默认调用是 ObjectOutputStream
的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。
用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,
比如可以在序列化的过程中动态改变序列化的数值。
(5)没有序列化接口的类是不能被反序列化的。当父类没有序列化接口的时候,
反序列化所得的对象必须通过默认构造函数构建父类对象,一层一层地得到,
当父类有序列化接口的时候,在序列化的时候它的字节信息已经被写在了文件里,
反序列化的时候便可直接得到该对象而不需要再调用构造函数了。
*/
public class Student implements Serializable{
private String stuno;
private String stuname;
/*transien关键字:在做对象序列化的时候让这个字段不被序列化
* 该元素不会进行jvm默认的序列化,也可以自己完成这个元素的序列化
*/
private transient int stuage;
public Student() {
}
public Student(String stuno, String stuname, int stuage) {
super();
this.stuno = stuno;
this.stuname = stuname;
this.stuage = stuage;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public String getStuname() {
return stuname;
}
public void setStuname(String stuname) {
this.stuname = stuname;
}
public int getStuage() {
return stuage;
}
public void setStuage(int stuage) {
this.stuage = stuage;
}
public String toString() {
return "Student:[stuno:" + this.stuno+
";stuname:" +this.stuname + ";stuage:"
+ this.stuage +"]";
}
//序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();//把jvm能默认序列化的元素进行序列化
s.writeInt(stuage);//自己完成suage的序列化
}
//反序列化
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();//把jvm能默认反序列化的元素进行反序列化操作
this.stuage = s.readInt();//自己完成stuage的反序列化
}
}
package 对象序列化和反序列化;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectSerializeDemo{
public static void main(String[] args) throws Exception{
String path = "D:\\就职学习\\Java\\Java基础\\io流\\src\\22.txt";
// //1.对象序列化
// ObjectOutputStream oos = new ObjectOutputStream(
// new FileOutputStream(path));
// Student stu = new Student("100","张三",20);
//
// oos.writeObject(stu);
//
// oos.flush();
// oos.close();
// System.out.println("成功");
//2.反序列化:
ObjectInputStream ois = new ObjectInputStream(
new FileInputStream(path));
Student stu1 = (Student)ois.readObject();
ois.close();
System.out.println(stu1);
}
}