IO 【vaynexiao】
程序员文章站
2024-03-02 23:00:22
...
https://edu.51cto.com/course/17347.html 汤小洋
基础
1. 简介
IO:Input Output 输入和输出流
- 通过IO流实现文件的输入和输出功能
- 用于对文件进行读写的操作
流stream:可以理解为一组有顺序的、有起点和终点的动态数据集合 - 文件是数据在硬盘上的静态存储
- 流是数据在传输时的动态形态
2. 文件的分类(两类)
- 文本文件
可以使用记事本编辑的文件, .txt .java .properties - 二进制文件
除了文本文件,其他所有文件都是二进制文件
InputStream是字节输入流的顶层父类,常用子类:
- FileInputStream
- ByteArrayInputStream
- ObjectInputStream
OutputStream是字节输出流的顶层父类,常用子类: - FileOutputStream
- ByteArrayOutputStream
- ObjectOutputStream
3. 流的分类(三类)
按流的方向(站在Java程序的角度)
- 输入流:用于读取数据,比如从文件中读取数据到程序中,由InputStream和Reader作为父类
- 输出流:用于写出数据,比如将程序中的数据写出到文件中,由OutputStream和Writer作为父类
按流中数据的单位 - 字节流byte:所操作的最小数据单元为字节,由InputStream和OutputStream作为父类
- 字符流char:所操作的最小数据单元为字符,由Reader和Writer作为父类,
【一个英文字符占1个字节,一个汉字占2个字节(GBK) 或 3个字节(UTF8)】
按数据的来源 - 节点流:直接对数据源进行操作,如操作文件
- 包装流:对一个节点流进行操作(包装)
基础API
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Date;
public class Test01 {
public static void main(String[] args) throws URISyntaxException, IOException {
//java.io.File
/*
* 创建一个File对象
*/
// 方式1:指定文件的全路径
// File file = new File("D:\\resource\\a.txt"); // 绝对路径
// File file = new File("D:/resource/a.txt");
// File file = new File("/home/soft01/a.txt");
// File file = new File("a.txt"); //相对路径
// 方式2:指定父目录的路径和文件名
// File file = new File("C:/resource", "code/a.txt");
// 方式3:指定父目录的File对象和文件名
File file1 = new File(new File("C:/resource"), "code/a.txt");
System.out.println("file1=:"+file1);//C:\resource\code\a.txt
// 方式4:指定URI统一资源标识符
File file2 = new File( Test01.class .getClassLoader() // 获取类加载器
.getResource("data.properties") // 加载类路径下的文件(当然文件得存在),返回URL(UniformResource Locator统一资源定位符)
.toURI() // 转换为URI(Uniform Resource Identifier统一资源标识符)
);
System.out.println("file2=:"+file2);//C:\idea_pro\io\target\classes\data.properties
File file = new File("c.txt"); // 放在项目根目录下才能找到,java默认是相对于项目的根目录
System.out.println("文件名:"+file.getName());//文件名:c.txt
System.out.println("路径名:"+file.getPath());//路径名:c.txt
System.out.println("绝对路径名:"+file.getAbsolutePath());//绝对路径名:C:\idea_pro\io\c.txt
System.out.println("父目录:"+file.getParent());//null
System.out.println("父目录文件对象:"+file.getParentFile()); //null 返回的是File对象
System.out.println("文件长度:"+file.length()+"字节");//文件长度:10字节
System.out.println("最后一次修改时间:"+new Date(file.lastModified()));//Sun May 10 16:59:38 CST 2020 lastModified()返回的是long值
System.out.println("是否可读:"+file.canRead());//是否可读:true
System.out.println("是否可写:"+file.canWrite());//是否可写:true
System.out.println("是否为普通文件:"+file.isFile());//是否为普通文件:true
System.out.println("是否为目录:"+file.isDirectory());//是否为目录:false
System.out.println("是否为隐藏文件:"+file.isHidden());//是否为隐藏文件:false
System.out.println(file); //c.txt 直接输出File对象,本质上就是调用getPath()
System.out.println(file.exists()); //true 判断指定路径的文件是否存在
/*
* 文件目录的操作
*/
File file3 = new File("C:/resource/c.txt");
boolean isSuccess = file3.createNewFile(); // 创建一个空文件,返回一个boolean,表示成功或失败
System.out.println("是否创建成功"+isSuccess);
file3.renameTo(new File("c2.txt")); //重命名 这里是相对路径会在项目根目录下新建c2.txt文件
boolean isSuccess2 = file3.delete(); //删除文件
System.out.println("删除是否成功"+isSuccess2);
File f = new File("D:/software");
// boolean isSuccess = f.mkdir(); // 创建目录,如果父目录不存在 ,会导致创建失败
// boolean isSuccess = f.mkdirs(); // 创建包括父目录的目录,即级联创建
// System.out.println(isSuccess);
String[] names = f.list(); // 获取目录下的所有文件和目录的名称
System.out.println(Arrays.toString(names));
File[] files = f.listFiles(); // 获取目录下的所有文件和目录的对象
System.out.println(Arrays.toString(files));
// 常量
System.out.println(File.separator);//当前系统分隔符
}
}
案例
递归获取指定目录下所有文件
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
public class Test01 {
public static void main(String[] args) throws URISyntaxException, IOException {
File file = new File("c:/idea_pro");
display(file);
}
public static void display(File file) {
// 判断文件是否存在
if (!file.exists()) {
return;
}
// 判断是否为目录
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
if(f.isFile()){
System.out.println(f.getAbsolutePath());
}else{
display(f);
}
}
}else{
System.out.println(file.getAbsolutePath());
}
}
}
递归删除全部空目录
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
public class Test01 {
public static void main(String[] args) throws URISyntaxException, IOException {
File file = new File("d:/resource");
remove(file);
}
public static void remove(File file) {
// 判断是否为空目录
if (file.isDirectory() && file.listFiles().length == 0) {
file.delete();
System.out.println("删除空目录:" + file.getAbsolutePath());
// 删除当前目录后可能导致父目录也为空,所以需要对父目录进行处理
remove(file.getParentFile());
} else if (file.isDirectory()) {
// 如果当前目录不为空目录,则获取目录下所有文件进行再处理
File[] files = file.listFiles();
for (File f : files) {
remove(f); // 递归删除
}
}
}
}
FileInputStream 文件字节输入流
import java.io.*;
import java.net.URISyntaxException;
public class Test01 {
public static void main(String[] args) throws URISyntaxException, IOException {
test01();
// test02();
// test03();
}
// 基本用法
public static void test01(){
FileInputStream fis = null;//不初始化时,close方法报错,怀疑可能未初始化
try {
//fis = new FileInputStream("a.txt");
fis = new FileInputStream(new File("a.txt"));// 读取项目根目录下的文件
/*
int data = fis.read(); //处于阻塞状态,读取一个字节返回int类型的字节值,a就是97,读取到末尾返回-1
while(data!=-1){
System.out.println((char)data);
data=fis.read();
}
*/
int data = -1;//初始值-1
while((data=fis.read()) != -1){
System.out.println(data+" : "+(char)data); // 字节流读取中文时可能会出现乱码(中文utf-8时是3个字节)
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
if(fis != null){ // 需要判断是否为null,防止出现NullPointerException
try {
fis.close(); // 关闭输入流:只要是打开了外部的资源(文件\数据库连接\网络连接),在使用后都需要关闭,释放资源
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 其他用法
public static void test02(){
// 在JDK7中,提供了一种新语法,叫做try-with-resource,能够自动关闭外部资源,不需要写finally,简化代码
try(
// 此处只能创建实现了AutoClosable接口的对象
FileInputStream fis=new FileInputStream("a.txt");
){
//System.out.println((char)fis.read());
//System.out.println(fis.available()); // 流中可读取的字节数
byte[] buffer=new byte[1024*1024]; // 减少对硬盘的读取次数,提高效率
// int num = fis.read(buffer); // 一次性读取buffer.length个字节到buffer中,返回实际读取到的字节数,如果读取到末尾,则返回-1
// System.out.println(num);
// String str = new String(buffer);
// System.out.println(str);
//
// num = fis.read(buffer);
// System.out.println(num);
//System.out.println(new String(buffer, 0, num)); // 将指定长度的字节数组转换为字符串
int num=-1;
while((num=fis.read(buffer)) != -1){
System.out.println(new String(buffer,0,num));
}
}catch(IOException e){
e.printStackTrace();
}
}
// 加载不同路径下的文件
public static void test03(){
try(
// 默认加载项目根路径下
//InputStream is=new FileInputStream("a.txt");
// 加载classpath类路径,即src目录
//InputStream is=Test01_FileInputStream.class.getClassLoader().getResourceAsStream("b.txt");
// 加载当前类所在目录
InputStream is=Test01.class.getResourceAsStream("c.txt");
){
System.out.println((char)is.read());
System.out.println("加载文件成功!");
}catch(IOException e){
e.printStackTrace();
}
}
}
FileOutputStream 文件字节输入流
import java.io.*;
public class Test01 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 如果文件不存在,会自动创建文件,如果文件存在,默认会覆盖原文件的内容
// fos=new FileOutputStream("a.txt");
fos = new FileOutputStream("a.txt", true); // true表示以追加的形式写数据
byte[] data = "hello world".getBytes();
fos.write(data); // 写入数据,只是将数据写入到内存的缓冲区中,并没有真正写入到文件中
fos.flush(); // 刷新输出流,完成数据的输出,当关闭流时会自动调用该方法
System.out.println("写入数据成功");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
单个文件复制
import java.io.*;
public class Test01 {
public static void main(String[] args) {
// 如果文件不存在,会自动创建文件,如果文件存在,默认会覆盖原文件的内容
// test01();
test02();
}
/*
* 每次复制一个字节 read()方法默认读取一个字节
*/
public static void test01(){
InputStream is = null;
OutputStream os = null;
try {
is = new FileInputStream("a.txt");
os = new FileOutputStream("aa.txt");
int data=-1;
while((data=is.read())!=-1){
os.write(data); // 读一个字节,写一个字节
}
System.out.println("文件复制成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 每次复制多个字节 read(arg)方法默认读取指定参数个字节
*/
public static void test02(){
try(
InputStream is = new FileInputStream("C:\\software\\oss-browser-win32-x64\\oss-browser.exe");
OutputStream os = new FileOutputStream("oss.exe");
){
byte[] buffer = new byte[1024*1024];
int num = -1;
while((num=is.read(buffer)) != -1){
os.write(buffer, 0, num);
}
System.out.println("文件复制成功");
}catch(IOException e){
e.printStackTrace();
}
}
}
复制目录下所有文件到目标目录
import java.io.*;
public class Test01 {
public static void main(String[] args) {
copyFile("C:/software","c:/backup");
}
public static void copyFile(String srcPath, String destPath) {
File srcFile = new File(srcPath);
File destFile = new File(destPath);
if(srcFile.isDirectory()){
destFile=new File(destPath+File.separator+srcFile.getName());
destFile.mkdirs();
File[] files = srcFile.listFiles();
for (File file : files) {
copyFile(file.getAbsolutePath(), destFile.getAbsolutePath());
}
}else if(srcFile.isFile()){
try(
InputStream is=new FileInputStream(srcFile);
OutputStream os=new FileOutputStream(destPath+File.separator+srcFile.getName());
){
byte[] buffer=new byte[1024*1024];
int num=-1;
while((num=is.read(buffer))!=-1){
os.write(buffer, 0, num);
}
System.out.println("复制"+srcPath);
}catch(IOException e){
e.printStackTrace();
}
}
}
}
字节数组输入输出流
import java.io.*;
public class Test01 {
public static void main(String[] args) {
// 流(数据)的来源或目的地并不一定是文件,也可以是内存中的一块空间,例如一个字节数组
// ByteArrayInputStream 字节数组输入流:从字节数组中读取数据,即将字节数组当作流输入的来源
// ByteArrayOutputStream 字节数组输出流:将数据写出到内置的字节数组中,即将字节数组当作流输出的目的地
test01();
test02();
}
// ByteArrayInputStream
public static void test01(){
byte[] data="welcome to java".getBytes();
try {
// 定义字节数组输入流,数据来源为字节数组
InputStream is = new ByteArrayInputStream(data);
int i=-1;
while((i=is.read())!=-1){
System.out.print((char)i);
}
//输出welcome to java
} catch (IOException e) {
e.printStackTrace();
}
/*
* ByteArrayInputStream和ByteArrayOutputStream不需要关闭
* 因为其操作的是内存中的字节数组,属于内存读写流,并非操作的外部资源
*/
}
// ByteArrayOutputStream
public static void test02(){
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 将数据写出到内置的字节数组中
os.write("hello".getBytes());
os.flush();
// 获取内置的字节数组中的数据
byte[] buffer = os.toByteArray();
System.out.println(new String(buffer));//hello
System.out.println(os.toString());//hello
} catch (IOException e) {
e.printStackTrace();
}
}
}
对象输入输出流
如果希望将Java对象写入到IO流中,或从IO流中读取Java对象,则要使用对象输入输出流,称为对象的序列化和反序列化
4.1 序列化和反序列化
序列化:将Java对象写入IO流中,实现将对象保存在磁盘上或在网络中传递对象
反序列化:从IO流中读取Java对象,实现从磁盘上或网络中恢复对象
要求:
对象必须实现Serializable接口,才能被序列化,转换为二进制流,通过网络进行传输
通过 serialVersionUID 判断对象的序列化版本的一致性:
在反序列时,会将流中的serialVersionUID与本地相应实体对象/类的serialVersionUID进行比较
如果相同就认为版本一致,则可以进行反序列化
如果不相同,则会出现序列化版本不一致的异常InvalidClassException
4.2 ObjectInputStream
对象输入流:用来读取对象,即反序列化
ObjectInputStream 和 ObjectOutputStream 属于包装流(用于对节点流进行功能扩展 / 包装)
在创建包装流,需要传入要操作的节点流对象
当关闭流时,只需要关闭包装流,被包装的节点流也会被关闭
4.3 ObjectOutputStream
对象输出流:用来写入对象,即序列化
User.java
import java.io.Serializable;
public class User implements Serializable {
// static final long serialVersionUID
// 根据类名、接口名、成员方法和属性等生成的一个64位的哈希值
// 表示对象类型的的唯一标识
private static final long serialVersionUID = 705661196096434175L;
private Integer id; // 都使用包装类型,默认为null
private String name;
private transient Integer age; // transient修饰的属性不会被序列化(static变量也不会被序列化)
private Address address; // 对象属性也必须实现Serializable接口
public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Address.java
import java.io.Serializable;
public class Address implements Serializable {
private String province;
private String city;
public Address() {
super();
}
public Address(String province, String city) {
super();
this.province = province;
this.city = city;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Address [province=" + province + ", city=" + city + "]";
}
}
Test.java
import java.io.*;
import java.util.Arrays;
import java.util.List;
public class Test01 {
public static void main(String[] args) {
test01();
test02();
}
// 序列化,写入对象
public static void test01() {
User u1 = new User(1001, "tom", 18);
u1.setAddress(new Address("江苏", "南京"));
User u2 = new User(1002, "jack", 21);
u1.setAddress(new Address("江苏", "扬州"));
List<User> users = Arrays.asList(u1, u2);
ObjectOutputStream oos = null;
try {
// FileOutputStream fos = new FileOutputStream("user.data");
// oos = new ObjectOutputStream(fos);
//输出到user.data文件中,是二进制文件,文本编辑器打开不能正常显示
oos = new ObjectOutputStream(new FileOutputStream("user.data"));
// 写入对象
// oos.writeObject(u1);
// oos.writeObject(u2);
oos.writeObject(users);
oos.flush();//这里不flush也行,后面有close
System.out.println("写入对象成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close(); // 只需要关闭包装流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 反序列化,读取对象
public static void test02() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("user.data"));
// 读取顺序和写入顺序一致
// User u1 = (User) ois.readObject();
// User u2 = (User) ois.readObject();
// System.out.println(u1);
// System.out.println(u2);
List<User> list = (List<User>) ois.readObject();
System.out.println(list);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件的拆分和合并
import java.io.*;
public class Test01 {
public static void main(String[] args) {
// 路径不包含bak的话报错,不知为何,总之不能在根目录下操作
splitFile("C:\\bak\\oss.zip");
mergeFile("C:\\bak\\oss.zip_1");
}
// 拆分文件:一个输入流,多个输出流
public static void splitFile(String filePath) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(filePath);
byte[] buffer = new byte[1024 * 1024 * 10]; // 每次读取10M
int num = -1;
int index = 0;
while ((num = fis.read(buffer)) != -1) {
fos = new FileOutputStream(filePath + "_" + (++index));
fos.write(buffer, 0, num);
fos.flush();
fos.close();
}
System.out.println("拆分成功,共拆分为:" + index + "个");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 合并文件:一个输出流,多个输入流
public static void mergeFile(String filePath) { //filePath只需要一个文件名,通过截取即可
String basePath = filePath.substring(0, filePath.lastIndexOf("_"));
FileOutputStream fos = null;
FileInputStream fis = null;
try {
fos = new FileOutputStream(basePath);
int index = 1;
File f = null;
while ((f = new File(basePath + "_" + index++)).exists()) {
fis = new FileInputStream(f);
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fos.write(buffer);
fos.flush();
fis.close();
}
System.out.println("合并成功:"+basePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件字符流
import java.io.*;
public class Test01 {
public static void main(String[] args) {
/*
* FileReader、FileWriter的用法与FileInputStream、FileOutputStream类似
* 前者是以字符为单位,后者是以字节为单位
*/
try(
Reader reader=new FileReader("User.java"); // 字符流无法读写二进制文件,
Writer writer = new FileWriter("User2.java")
){
//int data = reader.read(); // 每次读取一个字符,返回int类型的字符值
//System.out.println((char)data);
char[] buffer=new char[5];
int num = -1;
while((num=reader.read(buffer))!=-1){
writer.write(buffer, 0, num);
}
System.out.println("复制文件成功");
}catch(IOException e){
e.printStackTrace();
}
}
}
字符缓冲输入输出流 打印流
包装流 BufferedReader PrintWriter
import java.io.*;
public class Test01 {
public static void main(String[] args) {
try(
BufferedReader reader = new BufferedReader( new FileReader("a.txt") );
//BufferedWriter writer = new BufferedWriter(new FileWriter("aaaa.txt"));
PrintWriter writer = new PrintWriter("aaaa.txt");
){
//String data = reader.readLine(); // 每次读取一次,读不到数据时返回null
//System.out.println(data);
String data = null;
while((data = reader.readLine()) != null){
//writer.write(data);
//writer.newLine(); //插入换行符
//writer.write("\r\n"); // 也可以插入\r\n进行换行
writer.println(data); // 写入并换行,更方便
}
System.out.println("复制文件成功");
}catch(IOException e){
e.printStackTrace();
}
}
}
转换流
- 用于将字节流转换为字符流,同时可以实现编码的转换
- 在转换时需要指定使用的字符集,如果不指定默认使用JVM的字符集
- 在Java中没有提供将字符流转换为字节流的方法,不支持该操作
InputStreamReader
将字节输入流转换为字符输入流(InputStream - Reader)
OutputStreamWriter
将字节输出流转换字符输出流(OutputStream - Writer)
public class Test03_转换流 {
public static void main(String[] args) {
try(
// FileInputStream fis = new FileInputStream("a.txt");
// InputStreamReader isr = new InputStreamReader(fis, "gbk");
// BufferedReader reader=new BufferedReader(isr);
BufferedReader reader=new BufferedReader(
new InputStreamReader( new FileInputStream("b.txt") ,"gbk") // 以gbk编码读取文件
);
// BufferedReader reader = new BufferedReader(new InputStreamReader
// (Test03_转换流.class.getClassLoader().getResourceAsStream("b.txt")));
// BufferedWriter writer=new BufferedWriter(
// new OutputStreamWriter(
// new FileOutputStream("c.txt")
// ,"utf-8") // 以utf-8编码写入文件
// );
PrintWriter writer = new PrintWriter("c.txt", "utf-8"); // 这个最强大
){
// System.out.println(reader.readLine());
writer.write(reader.readLine());
System.out.println("复制文件成功");
}catch(IOException e){
e.printStackTrace();
}
}
}
RandomAccessFile
随机读写流,是一个字节流,可以对文件进行随机读写
- 随机:可以定位到文件的任意位置进行读写操作,通过移动指针(Pointer)来实现
- 读写:使用该流既能读取文件,也能写入文件
public class Test {
public static void main(String[] args) {
try(
/*
* 当文件不存在时:
* 如果模式为r,会报异常FileNotFoundException
* 如果模式为rw,会自动创建文件
*/
RandomAccessFile raf=new RandomAccessFile("x.txt", "rw"); //模式:r只读、rw读写
){
System.out.println(raf.getFilePointer()); // 获取当前指针的位置,从0开始
raf.write("张三".getBytes()); //对于utf-8,一个汉字占3个字节
raf.write("hello".getBytes());
System.out.println(raf.getFilePointer()); // 11
System.out.println("写入成功");
raf.seek(8); // 将指针移动到指定的位置
raf.write("李四".getBytes());
System.out.println(raf.getFilePointer()); // 14
raf.seek(6);
byte[] buffer = new byte[2];
raf.read(buffer);
System.out.println(new String(buffer));
System.out.println(raf.getFilePointer()); // 8
raf.skipBytes(3); // 将指针向后跳过指定的字节,只能往前,不能倒退 ——>
buffer = new byte[1024*1024];
int num = -1;
while((num = raf.read(buffer)) != -1){
System.out.println(new String(buffer,0,num));
}
// 修改数据
raf.seek(8);
raf.write("赵".getBytes());
System.out.println("修改成功");
}catch(IOException e){
e.printStackTrace();
}
}
}
文件的加密
* 实现文件的加密
* a.txt ——> a.txt.sec
*
* 思路:读取文件中的每个字节,与pwd进行异或的操作
*/
import java.io.*;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入文件路径:");
String filePath=input.nextLine();
System.out.print("请输入密码:");
int pwd = input.nextInt();
secret(filePath, pwd);
System.out.println("加密成功");
}
public static void secret(String filePath, int pwd){
try(
FileInputStream fis=new FileInputStream(filePath);
FileOutputStream fos = new FileOutputStream(filePath+".sec");
){
int data=-1;
while((data=fis.read())!=-1){
fos.write(data ^ pwd);
}
}catch(IOException e){
e.printStackTrace();
}
}
}