* IO流概述
* 可以将这种数据传输操作,看做一种数据的流动 , 按照流动的方向分为输入Input和输出Output
* Java中的IO操作主要指的是 java.io包下的一些常用类的使用. 通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)
*
* IO流的分类:
* 按照流的方向来分,可以分为:输入流和输出流.
* 按照流动的数据类型来分,可以分为:字节流和字符流
*
* 字节流:
* - 输入流 : InputStream
* - 输出流 : OutputStream
* 字符流:
* - 输入流 : Reader
* - 输出流 : Writer
*
*
* 一切皆字节:
* 计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制的形式存储的.
* 在数据传输时 也都是以二进制的形式存储的.
* 任何流 , 在传输时底层都是二进制.
File类:包含文件内容的读取和写出,是文件和目录路径名的抽象表示。
用户界面和操作系统使用依赖于系统的路径名字符串来命名文件和目录。此类提供了一个抽象的,与系统无关的分层路径名视图。
public class Demo1 {
public static void main(String[] args) throws IOException {
File dir = new File("d://haha/haha/xixi");
//boolean h = haaha.createNewFile();//创建文件
//文件创建异常:管理员运行、换盘
//System.out.println(h?"创建成功":"创建失败");
boolean i = dir.mkdirs();//创建文件夹:mkdirs可以多层目录创建
System.out.println(i?"success":"faild");
File a = new File(dir,"a.txt");
a.createNewFile();//使用父类文件dir创建文件(注意后面的第二个参数不能加路径)
File b = new File("d://haha","b.txt");
b.createNewFile();//使用路径创建文件
a.delete();//删除文件
System.out.println(b.getAbsolutePath());//获取文件的地址
System.out.println(b.getName());//返回此抽象路径名表示的文件或目录的名称。
System.out.println(b.getParent());//返回此抽象路径名父项的路径名字符串,如果此路径名未指定父目录,则返回 null 。
System.out.println(b.getParentFile());//返回此抽象路径名父项的抽象路径名,如果此路径名未指定父目录,则返回 null 。
System.out.println(b.length());//返回此抽象路径名表示的文件的长度。 单位:字节
}
}
在文件操作中,路径分割符和名称分隔符可以跨越操作系统使用,我们调用windows系统下的路径分割符和名称分隔符看下:
public class Demo2 {
public static void main(String[] args) throws IOException {
File a = new File("d:\\xixi");
a.createNewFile();
File b = new File("d:\\hahawocao");
b.createNewFile();
b.renameTo(a);//重命名此抽象路径名表示的文件。
System.out.println(File.pathSeparator);//路径分割符
System.out.println(File.separator);//名称分隔符
}
}
使用文件操作查找F盘下的doc文件
public class Demo3 {
public static void main(String[] args) {
File e = new File("f:\\");
File[] file = e.listFiles();
listFiles(file);
}
public static void listFiles(File[] files){
if(files != null && files.length > 0){
for (File f:files){
if(f.isFile()){//是文件
if(f.getName().endsWith(".doc")){
if(f.length()>100*1024*1024*512)
System.out.print("找到了一个doc文件:");
System.out.println(f);
}
}else{//是文件夹
File files2[] = f.listFiles();
listFiles(files2);//递归调用自己
}
}
}
}
}
文件过滤器的基本操作:
public class Demo4 {
public static void main(String[] args) {
File e = new File("f:");
listFiles(e);
}
public static void listFiles(File file){
//1、创建一个对象并描述规则
FileFilter filter = new AVIFileFilter();
//2、通过文件获取子文件夹
File[] files = file.listFiles(filter);
if(files != null && files.length>0){
for (File f:files) {
if(f.isDirectory()){
listFiles(f);
}else{
System.out.println("找到了一个avi文件:"+f.getAbsolutePath());
}
}
}
}
static class AVIFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".avi")||pathname.isDirectory())//是avi文件或者是文件夹
return true;//保留
return false;
}
}
}
可以对文件过滤器优化
public class Demo5 {
public static void main(String[] args) {
File e = new File("f:");
listFiles(e);
}
public static void listFiles(File file){
//1、创建一个对象并描述规则
FileFilter filter = new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".avi")||pathname.isDirectory())//是avi文件或者是文件夹
return true;//保留
return false;
}
};
//2、通过文件获取子文件夹
File[] files = file.listFiles(filter);
if(files != null && files.length>0){
for (File f:files) {
if(f.isDirectory()){
listFiles(f);
}else{
System.out.println("找到了一个avi文件:"+f.getAbsolutePath());
}
}
}
}
}
继续优化
public class Demo5 {
public static void main(String[] args) {
File e = new File("f:");
listFiles(e);
}
public static void listFiles(File file){
//1、创建一个对象并描述规则
//2、通过文件获取子文件夹
File[] files = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".avi")||pathname.isDirectory())//是avi文件或者是文件夹
return true;//保留
return false;
}
});
if(files != null && files.length>0){
for (File f:files) {
if(f.isDirectory()){
listFiles(f);
}else{
System.out.println("找到了一个avi文件:"+f.getAbsolutePath());
}
}
}
}
}
相对路径和绝对路径的理解:
public class Demo6 {
public static void main(String[] args) {
//相对路径:以盘符开始 例如c://a.txt
//绝对路径:java中是相对于项目目录路径 例如 a.txt
File file1 = new File("c://a.txt");
File file2 = new File("a.txt");
System.out.println("File1的路径"+file1.getAbsolutePath());
System.out.println("File2的路径"+file2.getAbsolutePath());
}
}
File1的路径c:\a.txt
File2的路径C:\Users\user\IdeaProjects\FileDemo1\a.txt
OutputStream的方法:
void close() 关闭此输出流并释放与此流关联的所有系统资源。
void flush() 刷新此输出流并强制写出任何缓冲的输出字节。
static OutputStream nullOutputStream() 返回一个新的 OutputStream ,它丢弃所有字节。
void write(byte[] b) 将 b.length字节从指定的字节数组写入此输出流。
void write(byte[] b, int off, int len) 将从偏移量 off开始的指定字节数组中的 len字节写入此输出流。
abstract void write(int b) 将指定的字节写入此输出流。
FileOutputStream:对文件进行写操作(字节流)
FileOutputStream fos =new FileOutputStream("f:\\a.txt");//append为true表示追加模式
byte[] bytes = "ABCDE".getBytes();
fos.write(bytes);
fos.write(bytes,2,2);
fos.write(99999);
fos.close();//尽可能早的关闭流
System.out.println("写入成功");
FileInputStream:对文件进行读操作(字节流)
文件操作中读取一个字节的方法(比较常用)
FileInputStream fis = new FileInputStream("f:\\a.txt");
while(true){
byte a = (byte)fis.read();//文件操作中读取一个字节的方法
if(a == -1)
break;
System.out.println((char) a);
}
fis.close();
文件操作中读取一个字节数组的方法(比较常用)
byte[] b =new byte[10];
int len = fis.read(b);
System.out.println(new String(b,0,len));
fis.close();
文件加密
我们知道,对一个变量进行异或两次就变成原来的变量,所以我们在加密文件时进行一次异或运算,然后再解密文件时再进行一次异或运算,就完成了一次简单的文件加密,具体代码如下:
/**
* 文件加密
*/
public class Demo10 {
public static void main(String[] args) throws IOException {
System.out.println("请输入要加密的文件路径:");
Scanner input = new Scanner(System.in);
//源文件
File oldFile = new File(input.nextLine());
//加密文件
File newFile = new File(oldFile.getParent(),"mima-"+oldFile.getName());
FileInputStream fis = new FileInputStream(oldFile);
FileOutputStream fos = new FileOutputStream(newFile);
while(true){
int b = fis.read();
if(b == -1)
break;
//任何数据^相同的数字两次结果就是其本身
fos.write(b^10);
}
}
}
FileWriter :对文件进行写操作(字符流)
public class Demo11 {
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("a.txt",true);//true表示是否追加原文件内容
//FileWriter fw2 = (FileWriter) fw.append("锄禾日当午,");
fw.append("锄禾日当午,").append("汗滴禾下土,").append("谁知盘中餐,").append("粒粒皆辛苦");
fw.flush();
fw.close();
}
}
FileWriter :对文件进行读操作(字符流)
public class Demo12 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
/* while(true){
int c = fr.read();
if(c == -1){
break;
}
System.out.print((char)c);
}*/
char[] c = new char[100];
int len = fr.read(c);
String text = new String(c,0,len);
System.out.println(text);
fr.close();
}
}
public class Demo13 {
public static void main(String[] args) throws IOException {
//转换流 :将字节流转换成字符流 使用了装饰者模式
FileInputStream fis = new FileInputStream("a.txt");
//将字节输入流转换为字符输入流 参数为要转换的字节流
//将字节输入流,转换为字符输入流
//参数1.要转换的字节流 参数2.指定编码名称(我的电脑采用的是UTF-8编码)
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
while (true){
int c = isr.read();
if(c==-1){
break;
}
System.out.print((char) c);
}
}
}
在我们每次对文件进行读操作结束后都要进行关闭资源,一般是放在Finally’块里面,其实在jdk1.7以后,我们可将创建对象的语句放在try块里,省去finally块,finally块会自动的执行。
import java.io.FileReader;
import java.io.IOException;
public class Demo19 {
public static void main(String[] args) throws IOException {
FileReader fr = null;
try {
fr = new FileReader("ddd.txt");
int c = fr.read();//读文件
System.out.println((char)c);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fr.close();//finally释放
//有可能fr没赋值,会发生空指针异常,扩大到Exception捕获
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
将创建对象的语句放在try块里
import java.io.FileReader;
import java.io.IOException;
public class Demo19 {
public static void main(String[] args) {
//FileReader fr = null;
try(FileReader fr = new FileReader("ddd.txt");){
//fr = new FileReader("ddd.txt");
int c = fr.read();//读文件
System.out.println((char)c);
} catch (IOException e) {
e.printStackTrace();
}
}
}
如若对象是以前创建的呢?在JDK1.9之后就可以这样写:
package com.wanmin.fileTest;
import java.io.FileReader;
import java.io.IOException;
public class Demo19 {
public static void main(String[] args) {
//FileReader fr = null;
FileReader fr = new FileReader("ddd.txt");
try(fr){
//fr = new FileReader("ddd.txt");
int c = fr.read();//读文件
System.out.println((char)c);
} catch (IOException e) {
e.printStackTrace();
}
}
}
多个流则可以在try里面用分号隔开
try(fr;pw){
……}
properties
public class Demo17 {
public static void main(String[] args) throws IOException {
/*Properties ppt = new Properties();
ppt.put("name","金苹果。");
ppt.put("info","讲述了果农辛勤种植苹果的过程.");
FileWriter fw = new FileWriter("c.properties");
ppt.store(fw,"说明");
fw.close();*/
Properties ppt = new Properties();
FileReader fr = new FileReader("c.properties");
ppt.load(fr);
System.out.println(ppt.getProperty("name"));
System.out.println(ppt.get("info"));
System.out.println(fr);
}
}
序列化
1.什么是序列化,什么是反序列化?
序列化是指把Java对象保存为二进制字节码的过程,反序列化是把二进制码重新转换成Java对象的过程。
序列化可以使对象永久地保存到硬盘上,通常存放在一个文件中,同时可以通过网络传输对象的字节序列。
package com.wanmin.fileTest;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Demo18 {
public static void main(String[] args) throws IOException {
Book1 b= new Book1("金苹果","果农辛勤种植苹果的过程。");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("book.txt"));
oos.writeObject(b);
oos.close();
System.out.println(b.toString());
}
}
class Book1 implements Serializable {
private String name;
private String info;
public Book1() {
}
public Book1(String name, String info) {
this.name = name;
this.info = info;
}
public String getName() {
return name;
}
public String getInfo() {
return info;
}
public void setName(String name) {
this.name = name;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Book1{" +
"name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}