字节流
字符流,转换流
细节:
输入流和输出流细节:
输入流:构造方法的路径,没有文件会抛出异常,FileNotFoundException,只能封装文件的路径,封装目录的路径是没意义的
输出流:构造方法的路径,没有文件会创建新文件,有文件会覆盖文件,且路径只能是文件,没有后缀名也是没有后缀名的文件,不是目录
输出流可能会有flush方法刷新缓冲区,输入流没有
字节流字符流细节:
字节是按照byte[] 输入输出或单个字节输入输出 , 字节流有available()方法,返回文件剩余字节数,字符流没有
字符流按照char[]数组输入输出或单个字节输入输出,注意writer还有按照String字符串输出的方法
字符流的输出流 有flush()
方法,用来把数组数据刷新到文件中(数组满了会自动刷新到文件中),字节输出流(OutputStream)没有,缓冲字节流(BufferedOutputStream)有
注意:字符流用于处理纯文本信息。而其它的声音 、视频、图片等需要用字节流处理。
缓冲字符流又多了 readLine()读一行 和 newLine()写换行符
各种流的复制(包括异常处理)
文件字节流复制
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class CopyInputStream {
public static void main(String[] args) {
//可能用到的方法; string.getBytes();把字符串转成byte数组,在写到文件里
//new String(byte[] b,int off,int len); 将byte数组转成字符串,控制台输出
try (
FileInputStream fis = new FileInputStream(new File("1.txt"));
FileOutputStream fos = new FileOutputStream(new File("2.txt"))
)
{
//定义缓冲数组
byte[] bytes = new byte[1024];
//定义读取个数
int readNum = 0;
while ((readNum = fis.read(bytes)) != -1) {
fos.write(bytes, 0, readNum);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
缓冲字节流复制
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyBufferedInputStream {
public static void main(String[] args) {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(
new FileInputStream(new File("1.txt")));
bos = new BufferedOutputStream(
new FileOutputStream(new File("2.txt")));
int readNum = 0;
byte[] bytes = new byte[1024];
while ((readNum = bis.read(bytes)) != -1) {
bos.write(bytes, 0, readNum);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件字符流复制
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyReader {
public static void main(String[] args) {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader(new File("1.txt"));
fw = new FileWriter(new File("2.txt"));
int readNum = 0;
char[] cbuf = new char[1024];//字符数组
while ((readNum = fr.read(cbuf)) != -1) {
fw.write(cbuf, 0, readNum);//存字符数组
fw.write(new String(cbuf, 0, readNum));//存字符串
// fw.write(str,0,readNum);//存字符串
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
缓冲字符流复制
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyBufferdReader {
public static void main(String[] args) {
try (
BufferedReader br = new BufferedReader(new FileReader(new File("1.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("2.txt")));
)
{
//定义读取的行
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);//写字符串
bw.newLine();//换行
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
复制整个文件目录
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 作者: 帅的一批 时间:2019年12月12日下午4:12:45 学习: 内容: 复制一个文件夹到另一个文件夹
*/
public class CopyFiles {
public static void main(String[] args) throws IOException {
File f1 = new File("E:\\File");
File f2 = new File("E:\\File1");
copyFiles2(f1, f2);
}
//单纯的复制文件
public static void copyFile2(File f1, File f2) throws IOException {
FileInputStream fis1 = new FileInputStream(f1);
FileOutputStream fos2 = new FileOutputStream(f2);
int readNum = 0;
byte[] bytes = new byte[1024];
while ((readNum = fis1.read(bytes)) != -1) {
fos2.write(bytes, 0, readNum);
}
System.out.println("复制文件" + f1.getAbsolutePath() + "到" + f2.getAbsolutePath() + "成功。");
}
/**
*
* @param f1 把f1复制一份给f2
* @param f2 把f1复制一份给f2
* @throws FileNotFoundException
* @throws IOException
*/
public static void copyFiles2(File f1, File f2) throws FileNotFoundException, IOException {
if (f1.getAbsolutePath().equals(f2.getAbsolutePath())) {
System.out.println("路径名一样,再见来不及握手。");
return;
} else if (!f1.exists()) {
System.out.println("文件或目录不存在,再见来不及握手");
return;
} else if (f2.getName().contains(".")) {
System.out.println("复制到的目录名格式错误,不要包含 '.' ");
return;
}
// 如果都是文件就复制
if (f1.isFile()) {
System.out.println("创建" + f2.getAbsolutePath() + "目录:" + f2.mkdir());
File newF2 = new File(f2.getAbsolutePath() + "//" + f1.getName());
copyFile2(f1, newF2);
}
// 如果都是目录,就遍历copy
if (f1.isDirectory()) {
File[] files = f1.listFiles();
if (files != null) {
for (File file : files) {
// 创建新文件路径,这个文件或文件夹与父目录一一对应。
File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
// 如果是文件夹就创建文件夹,如果是文件就创建文件;如果是文件夹,就继续遍历,一直找到文件为止;找到文件就复制
if (file.isDirectory()) {
// 目录 创建目录,修改流,再递归
// File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
System.out.println("创建" + newFile.getAbsolutePath() + "文件夹:" + newFile.mkdirs());
copyFiles2(file, newFile);
} else {
// File newFile = new File(f2.getAbsolutePath() + "\\" + file.getName());
copyFile2(file, newFile);
}
}
}
}
}
}
其他常见流
1.ByteArrayOutputStream 字节数组输出流(内存输出流)
放在内存中使用的,字节数组输出流又叫内存输出流。可以将数据写入到数组。
① 构造方法:
ByteArrayOutputStream()
② 常用方法:
1》write()
2》toString()
将写入数组缓冲区的内容转成字符串的形式
3》 toByteArray()
将写入数组缓冲区的内容转成字节数组的形式。
public class ByteArrayStreamStudy {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("abcdfg".getBytes());
System.out.println(baos.toString());
System.out.println(Arrays.toString(baos.toByteArray()));
}
}
2.RandomAccessFile 随机访问流(可读可写)
构造方法:
RandomAccessFile(File file, String mode)
其中 mode表示读写模式 :
r
表示只读,rw
表示读写 。
2》常用方法:
① seek(long pos)
设置文件指针的位置。
② getFilePointer()
获取文件指针的偏移量
注意: 随机插入覆盖(从索引后开始覆盖),不是插入。
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile(new File("1.txt"), "rw");
raf.seek(2);//设置指针位置
int value = raf.read();
System.out.println(raf.getFilePointer());//获取当前指针位置
//写入
raf.write("哈哈哈哈哈".getBytes());//插入覆盖,不是插入
System.out.println((char)value);
}
可以获取文件中任意位置的数据。比如可以获取某个字的索引,然后把它全部替换。
可用作分片上传,使用RandomAccessFile来切割文件。
https://blog.csdn.net/qq_66862911/article/details/131356420
注意:
RandomAccessFile依然 ==**不能向文件的指定位置插入内容**== ,如果直接将文件记录指针移动到中间某位置后开始输出,则**新输出的内容会覆盖文件中原有的内容**。如果需要向指定位置插入内容,程序需要先把插入点后面的内容读入缓冲区,等把需要插入的数据写入文件后,再将缓冲区的内容追加到文件后面。
/**
* 向指定文件的指定位置插入指定的内容
*
* @param fileName 指定文件名
* @param pos 指定文件的指定位置
* @param insertContent 指定文件的指定位置要插入的指定内容
*/
public static void insert(String fileName, long pos,
String insertContent) throws IOException {
RandomAccessFile raf = null;
//创建一个临时文件来保存插入点后的数据
File tmp = File.createTempFile("tmp", null);
FileOutputStream tmpOut = null;
FileInputStream tmpIn = null;
tmp.deleteOnExit();
try {
raf = new RandomAccessFile(fileName, "rw");
tmpOut = new FileOutputStream(tmp);
tmpIn = new FileInputStream(tmp);
raf.seek(pos);
//--------下面代码将插入点后的内容读入临时文件中保存---------
byte[] bbuf = new byte[64];
//用于保存实际读取的字节数
int hasRead = 0;
//使用循环方式读取插入点后的数据
while ((hasRead = raf.read(bbuf)) > 0) {
//将读取的数据写入临时文件
tmpOut.write(bbuf, 0, hasRead);
}
//----------下面代码插入内容----------
//把文件记录指针重新定位到pos位置
raf.seek(pos);
//追加需要插入的内容
raf.write(insertContent.getBytes());
//追加临时文件中的内容
while ((hasRead = tmpIn.read(bbuf)) > 0) {
raf.write(bbuf, 0, hasRead);
}
} finally {
if (raf != null) {
raf.close();
}
}
}
获取一个字符串中某个字符出现的索引位置及次数
public static int getNumOfChar(String str,char c) {
int count = 0;
int index = -1;
while ((index = str.indexOf(c, index+1)) != -1) {
System.out.println(index);
count++;
}
return count;
}
main(){
String str = "afddsadsafdsafdsafdsafdsdsafa";
syso(getNumOfChar(str,'s'))
}
3.打印流 PrintStream /PrintWriter
好处:打印流可以进行自动刷新,并且不会抛出 IOException。
println(char[] x) 打印字符数组时,返回值为字符数组的值。不是对象。
4.属性集 Properties
是Hashtable的子类,可以当做普通的Map使用;键值对方式
1.Properties 属性集 是一个键值对的集合。其中键与值都是字符串的形式。
2.构造方法 :
1》 Properties() 创建一个没有默认值的空属性集列表
3.常用方法:
** ① setProperty(key,value) 添加
** ② getProperty(String key) 获取
③ store(OutputStream out, String comments) 将属性集写入输出流
** ④ load(Reader reader) 将属性集加载到输入流中
get set使用
public static void main(String[] args) throws IOException {
Properties prp = new Properties();
System.out.println(prp);
prp.setProperty("username","root");
prp.setProperty("password", "123");
System.out.println(prp);
String name = (String) prp.get("username");
String psw = (String) prp.get("password");
System.out.println(name+psw);
}
把属性集写到配置文件中
public static void main(String[] args) throws IOException {
Properties prp = new Properties();
System.out.println(prp);
prp.setProperty("username","root");
prp.setProperty("password", "123");
System.out.println(prp);
prp.store(new FileWriter(new File("3.txt")), "用户名和密码");//把内存中的属性集写到文件里
}
3.txt中的结果
读取文件中的属性集
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties prp = new Properties();
prp.load(new FileInputStream(new File("3.txt")));
System.out.println(prp);//{password=123, username=root}
}
5.序列化流与反序列化流(重要)
1.序列化流/对象流 ObjectOutputStream
① 序列化:实现 Serializable 接口的类 称为可序列化的类。 该接口中没有任何的方法,就是为了表示该类所创建的对象能够被序列化。
2.构造方法:
① ObjectOutputStream(OutputStream out)
3…常用方法 :
① writeObject(obj)
注意: 必须写入实现了序列化的类的对象,才可以。否则抛出java.io.NotSerializableException
2.反序列化流 ObjectInputStream
1.构造方法
ObjectInputStream(InputStream in)
2.常用方法:
1》 readObject() 返回值是Object类型,返回的是读取的对象。
注意: 该方法不能判断是否存在对象,当到达文件末尾时,抛出异常EOFException 。
普通对象序列化反序列化使用:
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.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class ObjectOutputStreamStudy {
public static void main(String[] args) throws IOException, IOException, ClassNotFoundException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("4.txt")));
oos.writeObject(new Student("zcv", 12, 99.9));// 序列化流将对象放进文件中
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("4.txt")));
Student s = (Student) ois.readObject();//读取文件中的一个对象
System.out.println(s.getName());
ois.close();
}
}
class Student implements Serializable {
private String name;
private int age;
private double socore;
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;
}
public double getSocore() {
return socore;
}
public void setSocore(double socore) {
this.socore = socore;
}
public Student(String name, int age, double socore) {
super();
this.name = name;
this.age = age;
this.socore = socore;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
}
集合序列化反序列化使用
package day20.io.study2;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ObjectOutputStreamStudy2 {
public static void main(String[] args) {
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("a大师傅sf", 23));
persons.add(new Person("sa地方撒d", 22));
persons.add(new Person("a 大dsf", 2123));
persons.add(new Person("a爱的方式f", 1233));
persons.add(new Person("ad阿道夫f", 123));
persons.add(new Person(" 安抚dsf", 33));
try (
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("persons.txt")));
){
oos.writeObject(persons);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try (
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("persons.txt")));
){
ArrayList<Person> personList = (ArrayList<Person>) ois.readObject();
Iterator<Person> it = personList.iterator();
while (it.hasNext()) {
Person p = it.next();
if (p.getName().contains("a")) {
System.out.println(p);
}
}
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Person implements Serializable{
/**
*
*/
// private static final long serialVersionUID = 1L;
private String name;
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
细节
1.序列化版本号 :
(1)作用 :检测版本是否一致。
(2)serialVersionUID
①默认值为1L。一般都使用生成器生成随机值。
如果序列化时序列号版本号为1L,现在序列号为2L,在反序列化时会报java.io.InvalidClassException: 失效的类异常
2.序列化的对象存储问题:
1》当我们使用writeObject方法进行写入对象时,要求对象必须实现Serializable接口,
并且要求如果有对象属性,也必须实现该接口。
否则,会报