关于流的话就是它的种类比较杂,记忆起来比较复杂,因此操作起来往往不知道用哪个,很难受。
下面就是流的用法,就是单级以及多级的文件的复制以及数据录入
复制单级文件夹并改名字
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
//复制单级文件夹并该后缀名
//1.封装源文件夹
File srcFolder = new File("D:\\test");
//2.封装目标文件夹
File targetFolder = new File("E:\\test");
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
//复制文件夹
copyFolder(srcFolder, targetFolder);
System.out.println("复制完成!");
}
private static void copyFolder(File srcFolder, File targetFolder) throws IOException {
//获取源文件夹下所有的文件,复制并改名
File[] files = srcFolder.listFiles();
for (File f : files) {
copyFiles(f, targetFolder);
}
}
private static void copyFiles(File f, File targetFolder) throws IOException {
// System.out.println(targetFolder + "\\" + f.getName());
//读取源文件
FileInputStream in = new FileInputStream(f);
FileOutputStream out = null;
if (f.getName().endsWith(".jpg")) {
String newName = f.getName().substring(0, f.getName().lastIndexOf("."));
out = new FileOutputStream(targetFolder + "\\" + newName + ".png");
} else {
out = new FileOutputStream(targetFolder + "\\" + f.getName());
}
byte[] bytes = new byte[1024 * 8];
int len = 0;
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
out.flush();
}
in.close();
out.close();
}
public static void main(String[] args) throws IOException {
// 1.复制多级文件夹,复制过去后,把原文夹里面的 .jpg文件,后缀名改成 .png
File yuanfile = new File("D:\\test");
File xinfile = new File("E:\\test");
if (!xinfile.exists()) {
xinfile.mkdirs();
}
copyfile(yuanfile, xinfile);
}
private static void copyfile(File yuanfile, File xinfile) throws IOException {
File[] files = yuanfile.listFiles();
for (File f : files) {
if (f.isDirectory()) {
File file = new File(xinfile + "\\" + f.getName());
file.mkdirs();
copyfile(f, file);
} else {
fuzhifile(f, xinfile);
File file = new File(xinfile.getPath());
File[] files1 = file.listFiles();
for (File f1 : files1) {
if (f1.isFile() && f1.getName().endsWith(".jpg")) {
String absolutePath = f1.getAbsolutePath();
String substring = absolutePath.substring(0, absolutePath.lastIndexOf("."));
File newFile = new File(substring + ".png");
f1.renameTo(newFile);
}
}
}
}
}
private static void fuzhifile(File f, File xinfile) throws IOException {
FileInputStream in = new FileInputStream(f);
FileOutputStream out = new FileOutputStream(xinfile + "\\" + f.getName());
int len2 = 0;
byte[] bytes = new byte[1024 * 10];
while ((len2 = in.read(bytes)) != -1) {
out.write(bytes, 0, len2);
}
in.close();
out.close();
}
public static void main(String[] args) throws IOException {
//手动录入三个学生,按照总分排序,并将结果,存储到文本文件中保存起来
TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getTotalScore() - s2.getTotalScore();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return -num2;
}
});
for (int i = 1; i <= 3; i++) {
Student student = new Student();
Scanner sc = new Scanner(System.in);
System.out.println("请输入第" + i + "个学生的姓名");
String name = sc.nextLine();
student.setName(name);
System.out.println("请输入第" + i + "个学生的语文成绩");
int yw = sc.nextInt();
student.setChineseScore(yw);
System.out.println("请输入第" + i + "个学生的数学成绩");
int xx = sc.nextInt();
student.setMathScore(xx);
System.out.println("请输入第" + i + "个学生的英语成绩");
int yy = sc.nextInt();
student.setEnglishScore(yy);
//将三个学习放到集合中,并按照总分排序
set.add(student);
}
//遍历集合将学生的考试信息,保存到文本文件中
BufferedWriter writer = new BufferedWriter(new FileWriter(System.currentTimeMillis()+"studentScore.txt"));
//先输出表头
writer.write("学生序号" + "\t" + "学生姓名" + "\t" + "语文成绩" + "\t" + "数学成绩" + "\t" + "英语成绩" + "\t" + "总分");
writer.newLine();
writer.flush();
int index = 1;
for (Student student : set) {
writer.write(index + "\t" + student.getName() + "\t" + student.getChineseScore() + "\t" + student.getMathScore() + "\t" + student.getEnglishScore() + "\t" + student.getTotalScore());
index++;
writer.newLine();
writer.flush();
}
writer.close();
}
我之所以将上面几个例子粘出来,就是害怕自己忘记,反复记忆真难受。
数据输入输出流
它的特点就是能够读写基本数据类型
DataInputStream in = new DataInputStream(new FileInputStream(“a.txt”));
缺点就是怎么写的就怎么读,顺序不能乱。
内存操作流
在内存中进行读写操作,不关联文件
A:内存操作流的概述
a:操作字节数组
ByteArrayOutputStream
ByteArrayInputStream
此流关闭无效,所以无需关闭
b:操作字符数组
CharArrayWrite
CharArrayReader
c:操作字符串
StringWriter
StringReader
ByteArrayOutputStream,此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray () 和 toString () 获取数据。同时他也有将两个对象合成一个的功能。因为它的缓冲区会不断增长的缘故,因此只要将两者统统写入,然后通过下面方法将其转成字符数组,在转换:
char[] chars = charArrayWriter.toCharArray();
将两首歌合成一首
public static void main(String[] args) throws IOException {
FileInputStream in1 = new FileInputStream("上海滩.mp3");
FileInputStream in2 = new FileInputStream("曾经的你.mp3");
FileOutputStream out = new FileOutputStream("歌曲大连唱.mp3");
ArrayList<FileInputStream> list = new ArrayList<>();
list.add(in1);
list.add(in2);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len = 0;
for (FileInputStream inputStream : list) {
while ((len = inputStream.read(bytes)) != -1) {
byteArrayOutputStream.write(bytes, 0, len);
}
}
//取出内存中的字节数组
byte[] bytes1 = byteArrayOutputStream.toByteArray();
打印流
打印流:只是写,不操作源文件 就是单个的一个流,只用来输出
字节打印流 PrintStream
字符打印流 PrintWriter
PrintStream
PrintStream out2 = System.out; //他关联的设备是屏幕
out2.println(“abc”);
//这种方式关联的是文件
PrintStream stream = new PrintStream(new File(“c.txt”));
stream.println(“abc”);
stream.println(“abc”);
stream.println(“abc”);
stream.write(“welcome”.getBytes());
stream.close();
以上操作就可一直接写如连带换行。
PrintStream ps = new PrintStream(“d.txt”, “GBK”);
ps.write(“中文汉字”.getBytes());//这个写进去,用的是IDE 默认的编码
ps.println(“又是一个中文汉字”); //这个写进去,用的是你指定的编码
PrintWriter
构造方法:PrintWriter(OutputStream out, boolean autoFlush)
通过现有的 OutputStream 创建新的 PrintWriter。
PrintWriter pw = new PrintWriter(new FileOutputStream(“cc.txt”), true);
pw.write(“abc”);
如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作
pw.println(“abc”);
pw.flush();
pw.close();
IO流(打印流复制文本文件)
BufferedReader br = new BufferedReader(new FileReader(“studentScore.txt”));
PrintWriter printWriter = new PrintWriter(new FileWriter(“copy.txt”), true);
String line=null;
while ((line=br.readLine())!=null){
printWriter.println(line);
}
br.close();
printWriter.close();
键盘录入的第二种方式
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
System.out.println(“请输入字符串”);
String s = reader.readLine();
System.out.println(s);
//自定义一个结束标记
if(“886”.equals(s)){
break;
}
}
}
A:标准输入输出流概述
在System这个类中存在两个静态的成员变量:
- public static final InputStream in: 标准输入流, 对应的设备是键盘
- public static final PrintStream out: 标准输出流 , 对应的设备就是显示器
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的孙子类FilterOutputStream 的子类.
in是一个字节输入流对象,那么我们就可以通过这个字节输入流对象进行读取键盘录入的数据.- 那么我们既然要读取数据,之前我们讲解了两种读取数据的方式:
-
- 一次读取一个字节
-
- 一次读取一个字节数组
- 那么我们在这个地方使用那种读取方式. 经过分析,这两种读取方式都不太合适.因为数据是客户通过键盘录入进来的,而我们希望直接读取一行数据. 而既然要读取一行数据,那么我们就需要使用readLine方法,而这个方法是属于BufferedReader的方法,而我们就需要创建一个BufferedReader对象进行读取数据.而我们这in有属于字节流,而创建BufferedReader对象的时候需要一个字符流,而我们就需要将这个字节流转换成字符流,那么既然 要对其进行转换,那么就需要使用转换流. 需要使用InputStreamReader。
-
随机访问流概述和写出数据
RandomAccessFile概述 最大特点 能读能写
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
支持对随机访问文件的读取和写入。
RandomAccessFile的父类是Object , 这个流对象可以用来读取数据也可以用来写数据.可以操作任意数据类型的数据.
public static void main(String[] args) throws IOException {
RandomAccessFile raf = new RandomAccessFile("歌曲大联唱.mp3", "r");
RandomAccessFile raf2= new RandomAccessFile("歌曲大联唱2.mp3", "rw");
int len=0;
byte[] bytes = new byte[1];
int sum=0;
try {
while ((len = raf.read(bytes)) != -1) {
raf.seek(200);
raf2.write(bytes, 0, len);
}
}catch (Exception e){
long pointer = raf2.getFilePointer();
System.out.println(pointer);
}
}
序列化流和反序列化流的概述和使用
A:序列化流的概述
所谓的序列化:就是把对象通过流的方式存储到文件中.注意:此对象 要重写Serializable 接口才能被序列化
反序列化:就是把文件中存储的对象以流的方式还原成对象
序列化流: ObjectOutputStream
反序列化流: ObjectInputStream
//Serializable 一个对象可被序列化的一个标记接口
在使用序列化流时要注意如果你要将某个类的对象装入一个容器中去,那么这个容器也得实现Serializable 接口才行
ArrayList<Student> list = new ArrayList<>();
list.add(student);
list.add(student1);
list.add(student2);
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("list.txt"));
outputStream.writeObject(list);
像上面,你将同学类放入了List容器中,再去序列话,那么ArrayList也得实现Serializable 接口
class Student implements Serializable {
private static final long serialVersionUID = 5760262756605700379L;
//生成一个类的唯一id
private String name;
//transient 修饰成员变量后,此成员变量的就不会序列化到文件中
transient private int age;
ObjectInputStream stream = new ObjectInputStream(new FileInputStream(“student.txt”));
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(“student.txt”));
如何解决序列化时候的黄色警告线问题
我们的一个类可以被序列化的前提是需要这个类实现Serializable接口,就需要给这个类添加一个标记.
在完成序列化以后,序列化文件中还存在一个标记,然后在进行反序列化的时候,会验证这个标记和序列化前的标记是否一致,如果一致就正常进行反序列化,如果不一致就报错了. 而现在我们把这个类做了修改,将相当于更改了标记,而导致这两个标记不一致,就报错了.。
解决方法: private static final long serialVersionUID = 5760262756605700379L;
//生成一个类的唯一id
Properties的概述和作为Map集合的使用
Properties 类表示了一个持久的属性集。
Properties 可保存在流中或从流中加载。
属性列表中每个键及其对应值都是一个字符串。
Properties父类是Hashtable
- 属于双列集合,这个集合中的键和值都是字符串 Properties不能指定泛型
properties.setProperty(“大哥”, “弟弟”);
//String v = properties.getProperty(“大哥”);
//如果通过这个键,没有找到对应的值,会返回默认值
String v = properties.getProperty(“大哥大”, “备用”);
properties如果通过键找值没找到,则返回另一个,即输入的键是不存在的,则输出备用的值
把集合中的数据,保存到文件中去
properties.store(new FileWriter(“data.properties”),null);其中null是解释你这个文本的
A
:Properties的load()和store()功能
Properties和IO流进行配合使用:
- public void load(Reader reader): 读取键值对数据把数据存储到Properties中
- public void store(Writer writer, String comments)把Properties集合中的键值对数据写入到文件中,
SequenceInputStream
SequenceInputStream
表示其他输入流的逻辑串联。
它从输入流的有序集合开始,
并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,
依次类推,直到到达包含的最后一个输入流的文件末尾为止
a:构造方法
SequenceInputStream(InputStream s1, InputStream s2)
通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),
以提供从此 SequenceInputStream 读取的字节。
b:构造方法
SequenceInputStream(Enumeration<? extends InputStream> e)
通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
FileInputStream in1 = new FileInputStream("a.txt");
FileInputStream in2 = new FileInputStream("b.txt");
FileInputStream in3 = new FileInputStream("c.txt");
Vector<FileInputStream> v = new Vector<>();
v.add(in1);
v.add(in2);
v.add(in3);
Enumeration<FileInputStream> elements = v.elements();
FileOutputStream out = new FileOutputStream("d.txt");
SequenceInputStream sequenceInputStream = new SequenceInputStream(elements);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = sequenceInputStream.read(bytes)) != -1) {
out.write(bytes, 0, len);
out.flush();
}
out.close();
sequenceInputStream.close();
}