java中的多线程Thread十九个实例带你轻松学会
时间:2021-06-30 17:37:25
收藏:0
阅读:0
目录
IO流的概念(大纲):
1.InputStream和OutputStream的继承关系图
2.Reader和Writer的继承关系图
3.文件专属流(加※为重点掌握)
※FileInputStream(文件字节输入流)实例:
package fileInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
FileInputStream常用的方法
int available(); 返回流当中剩余的没有读到的字节数量
long skip(long n); 跳过几个字节不读
*/
public class FileInputStreamTest05 {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileInputStream fis = null;
try {
//1.要读取某一个文件,先与这个文件创建一个"输入流"
//String filePath = "afterglow.txt";//相对路径,相对当前而言,在当前路径下找
String filePath = "E:\\eclipse-workspace\\day26-IO\\InputStream\\fileInputStream\\afterglow.txt";//绝对路径
fis = new FileInputStream(filePath);
//读
System.out.println(fis.available());//共有多少个字节
byte[] bytes = new byte[fis.available()];//这种方式不太适合大文件,byte[]不能太大
int readByte = fis.read(bytes);
System.out.println(new String(bytes));
// readByte = fis.read();
System.out.println(fis.available());//剩余多少个字节没有读
//skip跳过几个字节不读
//fis.skip(3);
}catch(FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//在finally语句块中确保流一定关闭
if(fis!=null) {//避免空指针异常
//关闭流的前提是流不为空
try {
fis.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
}
※FileOutputStream(文件字节输出流)实例:
package fileOutputStream;
/*
文件字节输出流,负责写
从内存到硬盘
*/
import java.io.*;
public class FileOutputStreamTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileOutputStream fos = null;
try {
//fos = new FileOutputStream("myFile.txt");//先清空在写入
fos = new FileOutputStream("myFile.txt",true);//追加内容
byte[] bytes = {97,98,99,100};
//byte[] bytes = {‘a‘,‘b‘};
//fos.write(bytes);//ab
fos.write(bytes, 0, 1);//a
String str = "无为在歧路";
fos.write(str.getBytes());//字符串转换为字符数组
//写完之后要刷新
fos.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}catch(NullPointerException e) {
e.printStackTrace();
}
finally {
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
如何利用FileInputStream和FileOutputStream实现单个文件的copy?
package copy;
/*
使用FileInputStream和FileOutputStream完成文件的拷贝
拷贝的过程应该是一边读一边写
使用以上的字节流拷贝文件的时候,文件类型没有限制
*/
import java.io.*;
public class Copy01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//创建一个输入流对象
fis = new FileInputStream("afterglow.txt");
//创建一个输出流对象
fos = new FileOutputStream("copy.txt");
//核心内容:一边读一边写
byte[] bytes = new byte[1024*1024];//一次最多拷贝1MB
int readCount = 0;
while((readCount=fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}
//输出流需要刷新
fos.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fis != null) {
try {
fis.close();
}catch(IOException e) {
e.printStackTrace();
}
}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
我们成功的使用代码复制了文件,当然此处可以复制任意的文件类型,就不一一演示
FileReader(文件字符输入流)实例:
package fileReader;
/*
文件字符输入流,只能读取普通文本
读取文本内容时,比较方便快捷
*/
import java.io.*;
public class FileReaderTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileReader reader = null;
try {
reader = new FileReader("afterglow.txt");
//读
char[] chars = new char[4];//一次读取4个字符
int readCount = 0;
while((readCount = reader.read(chars)) != -1) {
System.out.print(new String(chars,0,readCount));
}
}catch(FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileWriter(文件字符输出流)实例:
package fileWriter;
import java.io.FileWriter;
import java.io.IOException;
/*
文件字符输出流,写
只能输出普通文本
*/
public class FileWriterTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileWriter out = null;
try {
//创建文件字符输出流对象
out = new FileWriter("FileWriter.txt");
//开始写
char[] chars = {‘我‘,‘是‘,‘种‘,‘花‘,‘家‘,‘|‘};
out.write(chars);
out.write(chars,2,4);
out.write("\n");
out.write("我是亚托克斯,我是世界的终结者");
//刷新
out.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if(out != null) {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
写入完成,如下图
如何利用FieReader和FileWriter实现单个文件的copy?
package copy;
import java.io.*;
public class Copy02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
FileReader in = null;
FileWriter out = null;
try {
in = new FileReader("afterglow.txt");
out = new FileWriter("copy2.txt");
char[] chars = new char[1024];//1MB
int readCount = 0;
while((readCount = in.read(chars)) != -1) {
out.write(chars,0,readCount);
}
out.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(in != null) {
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(out != null) {
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
实现成功,如下图(采用字符流复制只能复制纯文本文件)
关于文件copy的总结:
其实使用FileInputStream和FileOutputStream复制文件和FileReader和FileWriter复制文件从本质上来说是相同的,因为过程如下图所示
graph TD
创建读取文件和写入文件的对象 --> 创建一个数组用来存放读取到的数据-->写入新的文件中-->最后关闭所有进程
4.缓冲流(只讲个例)
BuffteredReader(带有缓冲区的字符输入流)实例:
package bufferedReader;
/*
带有缓冲区的字符输入流
使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲
*/
import java.io.*;
public class BuffteredReaderTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//当一个流的构造方法中需要一个流的时候,被传进来流叫做节点流
//外部负责包装的这个流叫做包装流/处理流
//就当前而言:FileReader是一个一个节点流;BufferedReader是一个包装流/处理流
FileReader reader = null;
BufferedReader br = null;
try {
reader = new FileReader("afterglow.txt");
br = new BufferedReader(reader);
//readLine()不带换行符
String s = null;
while((s = br.readLine()) != null) {
System.out.println(s);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//关闭流:只需要关闭包装流,节点流自动关闭(源码)
try {
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
BufferedWriter(带有缓冲的字节输出流)实例:
(此处为了节省时间采用了throws抛出异常,平时大家写代码尽量使用try-catch语句块)
package bufferedWriter;
/*
带有缓冲的字节输出流
*/
import java.io.*;
public class BufferedWriterTest01 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
BufferedWriter out = new BufferedWriter(new FileWriter("BufferedWriter.txt"));
out.write("NIHAODIQIU");
out.write("\n");
out.write("Yeah!");
//刷新
out.flush();
out.close();
}
}
5.转换流(只讲个例)
InputStreamReader(字节流转换为字符流)实例:
package inputStreamReader;
/*
转换流 InputStreamReader 将字节流转换为字符流
*/
import java.io.*;
public class InputStreamReaderTest01 {
//此处为了节省时间采用了throws抛出异常,平时大家写代码一定尽量使用try-catch语句块
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
/*
* //字节流 FileInputStream in = new FileInputStream("copy.txt"); //通过转换流转换
* InputStreamReader reader = new InputStreamReader(in);//in是节点流,reader是包装流
* //字符流 BufferedReader br = new BufferedReader(reader);//该构造方法只能传字符流,不能传字节流
*/
//改进:合并
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("copy.txt")));
String s = null;
while((s = br.readLine()) != null) {
System.out.println(s);
}
//关闭最外层的包装流
br.close();
}
}
6.数据流
DataOutputSteam(数据字节输出流)实例:
package dataOutputStream;
/*
数据专属流
这个流可以将数据连同数据的类型一并写入文件
注意:这个文件不是普通的文本文档(记事本打不开)
*/
import java.io.*;
public class DataOutputSteamTest01 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//创建数据专属的字节输出流
//此处创建的文件可以是任何后缀,只有DataInputStream能打开并读取
DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.a"));
//定义数据
byte b = 97;
short s = 200;
int i = 300;
long l = 400L;
float f = 3.14f;
double d = 3.1415926;
char c = 97;
boolean flag = false;
//写数据
dos.writeByte(b);
dos.writeShort(s);
dos.writeInt(i);
dos.writeLong(l);
dos.writeFloat(f);
dos.writeDouble(d);
dos.writeChar(c);
dos.writeBoolean(flag);
dos.flush();
dos.close();
}
}
DataInputStream(数据字节输入流)实例:
package dataInputStream;
/*
数据字节输入流
DataOutputStream写的文件只能使用DataInputStream去读,并且读的顺序必须和写的顺序一致
*/
import java.io.*;
public class DataInputStreamTest01 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
DataInputStream dis = new DataInputStream(new FileInputStream("data.a"));
byte b = dis.readByte();
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
char c = dis.readChar();
boolean flag = dis.readBoolean();
System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(c);
System.out.println(flag);
dis.close();
}
}
经检查,读取的数据与写入的数据一致。
7.标准输出流(只讲个例)
※PrintStream(字节输出流)实例:
package printStream;
import java.io.FileOutputStream;
import java.io.PrintStream;
/*
标准的字节输出流。默认输出到控制台
日志框架的实现原理
*/
public class PrintStreamTest01 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
PrintStream ps = System.out;
ps.print("你好,呆呆");
ps.print("你好,棉花");
ps.print("你好,李肖瑶");
//可以改变标准输出流的输出方向吗?可以
//标准输出流不在指向控制台,指向了"PrintStream.txt"文件
PrintStream printStream = new PrintStream(new FileOutputStream("PrintStream.txt"));
System.setOut(printStream);
System.out.println("aha my baby");
System.out.println("Second Line");
//标准输出流不需要手动关闭
}
}
利用PrintStream实现的日志工具:
大家在写代码一定要仔细,不然你怎么找都找不到那里发生了错误(笑)
package logUtil;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
日志工具
*/
public class LogUtil {
public static void main(String[] args) {
// TODO Auto-generated method stub
LogUtil.log("hello");
LogUtil.log("调用了System类的gc方法,建议启动垃圾回收");
LogUtil.log("调用了UserService的doSome方法");
LogUtil.log("用户尝试登录,验证失败");
}
public static void log(String msg) {
try {
//指向日志文件
//PrintStream printStream = new PrintStream(new FileOutputStream("Log.txt"),true);
//第一次输代码的时候粗心传参时传错了位置,导致检查了半个小时没发现问题的结果,
//在后边慢慢梳理发现每一次传参都会刷新文件,然后把两个new分开写了一遍后发现了问题是构造方法传参的true放错了位置,
//所以说大家一定要仔细啊,一个小问题都有可能引发一场灾难
PrintStream printStream = new PrintStream(new FileOutputStream("Log.txt",true));//不清空
//改变输出方向
System.setOut(printStream);
//当前时间
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strTime = sdf.format(nowTime);
//输出
System.out.println(strTime + " :" + msg);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
结果如下图:
8.对象流
图解序列化(ObjectOutputStream)和反序列化(ObjectInputStream):
由上图我们可以得知:
ObjectOutputStream是用来序列化的,即把对象从内存拆分到硬盘中
ObjectInputStream是用来反序列化的,即把对象从硬盘恢复到内存中
在序列化的过程中可以使用transient关键字表示游离的,不参与序列化
当然,我们需要知道参与序列化和反序列化必须实现Serializable接口,源码如下:
public interface Serializable {
}
该接口只是一个标志性接口,java虚拟机可以识别,并自动生成一个序列化版本号
这个版本号有什么用呢?
我们要知道java语言中是采用什么机制来区分类的?
1.类名
2.序列化版本号
如果类名相同的两个类都实现了Serializable接口
优点:java虚拟机技能区分开他们,因为他们的序列化版本号不同
缺点:后续不能修改代码(重新编译会生成新的序列版本号)
结论:
建议给实现了Serialzable接口的类提供一个不变的序列版本号
这样更新这个类就不会影响我们的反序列化
定义一个Student类用来存放数据:
package objectOutputStream;
import java.io.Serializable;
public class Student implements Serializable{
@Override
public String toString() {
return "Student [no=" + no + ", name=" + name + ", age=" + age + "]";
}
//固定一个序列版本号,这样更新这个类就不会影响反序列化
private static final long serialVersionUID = 89821732739371298L;
//transient关键字表示游离的,不参与序列化
//private transient int no;
private int no;
private String name;
private int age;//增加属性也不会报错
public Student() {
}
public Student(int no, String name) {
this.no = no;
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
※ObjectOutputStream实例:
package objectOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
public class ObjectOutputStreamTest01 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
Student s = new Student(1111,"zhaoxinyu");
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ObjectOutputStream.txt"));
//序列化对象
oos.writeObject(s);
List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(1234,"zhangjing"));
studentList.add(new Student(5678,"LIUXUETING"));
studentList.add(new Student(43133,"YUEYANG"));
ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream("ObjectOutputStream2.txt"));
oos2.writeObject(studentList);
//刷新和关闭
oos.flush();
oos.close();
oos2.flush();
oos2.close();
}
}
※ObjectInputStream实例:
package objectInputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.List;
import objectOutputStream.Student;
/*
反序列化
*/
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ObjectOutputStream.txt"));
//开始反序列化,读
Object obj = ois.readObject();
//反序列化返回一个学生对象,会调用学生的toString方法
System.out.println(obj);
ois.close();
//反序列化集合
ObjectInputStream ois2 = new ObjectInputStream(new FileInputStream("ObjectOutputStream2.txt"));
//开始反序列化,读
Object obj2 = ois2.readObject();
//反序列化返回一个学生对象,会调用学生的toString方法
//System.out.println(obj2);
List<Student> studentList = (List<Student>)obj2;
for(Student student:studentList) {
System.out.println(student);
}
System.out.println(obj2 instanceof List);
ois2.close();
}
}
9.File类
File类中常用的方法实例1
boolean exists();判断文件存不存在
boolean createNewFile();以文件形式新建
boolean mkdir();以目录形式新建
boolean mkdirs();以多重目录形式新建
String getParent();获取文件的父路径,返回String
File getParentFile();获取文件的父路径,返回File
String getAbsolutePath();获取文件的绝对路径
package file;
import java.io.File;
import java.io.IOException;
public class FileTest01 {
public static void main(String[] args) throws IOException {
File f1 = new File("after.txt");
System.out.println(f1.exists());//false
File f2 = new File("afterglow.txt");
System.out.println(f2.exists());//true
// if(!f1.exists()) {
// f1.createNewFile();//新文件
// }
if(!f1.exists()) {
f1.mkdir();//新目录
}
File f3 = new File("a\\b\\c");
if(!f3.exists()) {
f3.mkdirs();//新多重目录
}
//获取文件的父路径
String parentPath = f2.getParent();
System.out.println(parentPath);//null,相对路径的当前路径下父路径为空
parentPath = f3.getParent();
System.out.println(parentPath);//a\b,相对路径下的当前路径从根目录开始
File parentFile = f3.getParentFile();//绝对路径
System.out.println(parentFile.getAbsolutePath());
//E:\eclipse-workspace\day26-IO\a\b
System.out.println(f2.getAbsolutePath());
//E:\eclipse-workspace\day26-IO\afterglow.txt
}
}
File类中常用的方法实例2
boolean delete();删除文件
String getName();获取文件名
boolean isDirectory();判断是否是一个目录
boolean isFile();判断是否是一个文件
long lastModified();最后一次修改时间(从1970.1.1开始的总毫秒数)
long length();获取文件大小
package file;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FileTest02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File f1 = new File("E:\\eclipse-workspace\\day26-IO\\afterglow.txt");
System.out.println("文件名:"+f1.getName());
//判断是否是一个目录
System.out.println(f1.isDirectory());//false
//判断是否是一个文件
System.out.println(f1.isFile());//true
System.out.println(f1.lastModified());
//转换成日期
Date time = new Date(f1.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
System.out.println(sdf.format(time));//2021-04-06 15:47:00 561
System.out.println(f1.length());//9
}
}
File类中常用的方法实例3
File[] listFiles();获取当前目录下所有的子目录
package file;
import java.io.File;
public class FileTest03 {
public static void main(String[] args) {
// TODO Auto-generated method stub
File f1 = new File("E:\\eclipse-workspace\\day26-IO\\bin");
File[] files = f1.listFiles();
for(File file : files) {
System.out.println(file.getName());
// System.out.println(file.getAbsolutePath());
}
}
}
10.利用File类常用方法和FileInputStream和FileOutputStream实现文件夹的复制(包含文件夹下所有内容)
源文件路径:D:\java_copy\a
目标文件路径:D:\java_copy\copytext
文中提到的变量名含义:
yuan:源文件
mubiao:目标文件
length:源文件路径名长度
newFile:目标文件中新增的文件
sonmulu1:文件夹的目录下所有文件
文件夹复制的代码实现及思路:
思路:一层一层的复制
graph TD
要分层实现复制
-->那么每打开一层就要复制该层下的所有文件
-->程序调用自身
-->使用递归
递归是指程序经过不断调用自身得出结果的方法
graph TD
在每一层中复制所有文件-->使用迭代-->判断该文件是文件夹还是文件--文件夹-->使用mkdirs来创建多重目录-->循环结束
判断该文件是文件夹还是文件--文件-->使用createNewFile来创建文件-->循环结束
迭代是循环,是把本次循环的结果当做下一次循环的初值的方法
代码如下:
package copy;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Copy03 {
public static void main(String[] args) {
File yuan = new File("D:\\java_copy\\a");
int length = new String("D:\\java_copy\\a").length();//获取源文件路径名长度
File mubiao = new File("D:\\java_copy\\copytext");
if(!mubiao.exists()) {
mubiao.mkdirs();
}
copy(yuan,mubiao,length);
}
public static void copy(File yuan,File mubiao,int length) {
//复制文件
if(yuan.isFile()) {
FileInputStream f1 = null;
FileOutputStream f2 = null;
String str = (mubiao.getAbsolutePath()+yuan.getAbsolutePath().substring(length));
//System.out.println(str);//测试路径是否正确
File newFile = new File(str);
try {
f1 = new FileInputStream(yuan);
if(!newFile.exists()) {
newFile.createNewFile();
}
f2 = new FileOutputStream(newFile);
byte[] bytes = new byte[1024*1024];//1MB
int readCount = 0;
while((readCount = f1.read(bytes)) != -1) {
f2.write(bytes,0,readCount);
}
f2.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if(f1!=null) {
try {
f1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(f2!=null) {
try {
f2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return;
}
File[] sonmulu1 = yuan.listFiles();
for(int i = 0;i<sonmulu1.length;i++) {
//复制目录
if(sonmulu1[i].isDirectory()) {
String str = (mubiao.getAbsolutePath()+sonmulu1[i].getAbsolutePath().substring(length));
//System.out.println(str);//测试路径是否正确
File newFile = new File(str);
if(!newFile.exists()) {
newFile.mkdirs();
}
}
copy(sonmulu1[i],mubiao,length);
}
}
}
11.IO+Properties的联合使用
代码示例:
package test;
import java.io.*;
import java.util.Properties;
public class IOPropertiesTest01 {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
//新建输入流对象
FileReader reader = new FileReader("userinfo");
//新建一个Map集合
Properties pro = new Properties();
//调用Properties对象的Load()方法将文件中的数据加载到Map集合中
pro.load(reader);//文件中的数据顺着管道加载到Map集合中,其中等号左边做key,右边做value
//通过key来获取value
String username = pro.getProperty("username");
System.out.println(username);
String password = pro.getProperty("password");
System.out.println(password);
String date = pro.getProperty("date");
System.out.println(date);
reader.close();
}
}
评论(0)