I/O主要是对文件进行处理,主要包括三个方面的内容:一个是Input(输入);另一个是out(输出);还有一个FIle。
|
1.文件
1.1文件操作 File类
Java中文件夹操作的所有类都在java.io这个包里面,该包下面有一个FIle类,可以操作文件,但是该类只能创建文件、删除文件、对文件属性进行操作。不能对文件里面的内容进行读写操作。
在磁盘上寻找文件需要路径,分为绝对路径和相对路径
- 绝对路径:从根文件开始的路径,以“\”作为开始。
- 相对路径:从当前文件夹开始的路径。
文件常见属性操作:
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
/**
* 文件常见属性操作
*/
public class FileDome {
public static void main(String[] args) throws IOException {
testFile();
}
public static void testFile() throws IOException {
Scanner sc = new Scanner(System.in);
System.out.println("1.查看文件属性");
System.out.println("删除文件");
// 第一步,创建File对象
File file = new File("E:", "Hello.java");
// 如果选择2就删除文件
String line = sc.nextLine();
if (line.equals("2")) {
file.deleteOnExit();
return;// ???????
}
// 第二步,进行相应的操作
// 如果文件不存在,创建一个新文件
if (!file.exists()) {
file.createNewFile();
}
// 判断是否可以执行
String canExe = file.canExecute() ? "可以执行" : "不可以执行";
// 判断是否可读
String canRead = file.canRead() ? "可以读" : "不可以读";
// 判断是否可写
String canWrite = file.canWrite() ? "可以写" : "不可以写";
//绝对路径
String abFile = file.getAbsolutePath();
//获取父目录
String parent = file.getParent();
//判断是否为文件
String isFile = file.isFile()?"是文件":"是文件夹";
//判断是否为绝对路径
String isAb = file.isAbsolute()?"是绝对路径":"相对路径";
//判断是否为文件夹
String isDir = file.isDirectory()?"是文件夹":"是文件";
//判断是否为隐藏
String isHidden = file.isHidden()?"隐藏文件":"不是隐藏文件";
//文件的长度
long len = file.length();
//最后一次修改时间
SimpleDateFormat sft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String lastMod = sft.format(new Date(file.lastModified()));
System.out.println(canExe);
System.out.println(canRead);
System.out.println(canWrite);
System.out.println("绝对路径:"+abFile);
System.out.println("父目录:"+parent);
System.out.println(isFile);
System.out.println(isAb);
System.out.println(isDir);
System.out.println(isHidden);
System.out.println(len);
System.out.println("最后一次修改时间:"+lastMod);
}
}
/* 执行结果
* 1.查看文件属性 删除文件 1 可以执行 可以读 可以写 绝对路径:E:\Hello.java 父目录:E:\ 是文件 是绝对路径 是文件 不是隐藏文件
* 0 最后一次修改时间:2017-03-25 06:26:49
*/
1.2目录管理File.listFiles()
File类中有一个
listFiles()方法可以搜索出某个目录下面所以方法,但是目录下面还有目录,也是要搜索的,这是可以使用递归。
示例:搜索整个目录
import java.io.File;
public class ListFile {
public static void main(String[] args) {
File file = new File("E:\\C\\Desktop\\gameec");
list(file);
}
private static void list(File _file) {
File[] fs= _file.listFiles();
for(File f:fs){
if(f.isDirectory()){//如果有文件夹
list(f);
}
System.out.println(f);
}
}
}
运行结果
E:\C\Desktop\gameec\Game-EC模块\Game-EC 6.8[加密狗版].ec
E:\C\Desktop\gameec\Game-EC模块\Game-EC-6.X[加密狗版].ec
E:\C\Desktop\gameec\Game-EC模块
E:\C\Desktop\gameec\Game-ec破解版.ec
E:\C\Desktop\gameec\VC6迷你连接器.zip
E:\C\Desktop\gameec\注入器.exe
E:\C\Desktop\gameec\源码\dll.e
E:\C\Desktop\gameec\源码\注册程序.e
E:\C\Desktop\gameec\源码
2.流和流的分类
在Java宗,每个流都是一个对象,流通常分为两种:
- 输入流(InputStream):只要从流当中不停的把字节取出即可
- 输出流(OutputStream):只要把准备好的字符串传给它即可
- 外部系统------(输入流)→→→处理逻辑-------(输出流)→→→外部系统
- Java的字节流 InputStream是所以字节输入流的父类,而OutputStream是所以字节输出流的父类。
- Java的字符流 Reader是所以读取字符串输入流的父类,而Writer是所以输出字符串的父类。
字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer
在Java中所以的字节流都是以Stream结尾的,所以的字符流都是以Reader/Writer结尾的。如下图
2.1字节流和字符流
输入流代表从外部流入计算机的数据序列,输出流代表从计算机流入外部的数据序列。
Java对于流的操作可以分为字节流和字符流。
字节流主要操作字节序列的对象,如对二进制文件、图片及音像文件的操作;
字符流主要操作字符序列的对象,如对文本文件等。
2.1.1字节流
(1)输出字节流OutputStream
- OutputStream是所以的输出字节流的父类,它是一个抽象类
- ByteArrayOutputStream、FIleOutputStream是两种基本的介质流,它们分别向Byte的数组和本地文件写入数据。ObjectOutputStream和所有的FIlerOutputStream的子类都是装饰流。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* 使用字节流输出内容、读取内容
*/
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
out();
}
private static void out() throws IOException {
OutputStream out = null;
// 如果在关闭前程序出现异常,文件就不能关闭,所以应该将关闭放在finally里,不管程序有无异常,都应该关闭流
try {
// 第一步获得对象
out = new FileOutputStream("D:/Hello.java");// 如果D:/Hello.java不存在,会默认创建一个
// 如果在直接使用out对象写入,只会覆盖前面的数据,下面个对象会在后面添加新数据
// OutputStream out2 = new FileOutputStream("D:/Hello.java", true);
// 输出的内容
String info = "Hello Java!";
// 将内容转换成字节数组
byte[] buf = info.getBytes();
// 写到文件里
out.write(buf);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭
out.close();
}
}
}
(2)输入字节流InputStream
- InputStream是所以的输入字节流的父类,它是一个抽象类
- ByteArrayInputStream、StringBufferInputStream、FileInputStream是三种基本的介质流,它们分别从Byte的数组、StringBuffer和本地文件中读取数据。ObjectInputStream和所有的FIlerInputStream的子类都是装饰流。
import java.io.FileInputStream;
public class FileInputStreamDemo {
public static void main(String[] args) {
// 第一步获得对象
FileInputStream in = null;
try {
in = new FileInputStream("D:/Hello.java");
// 开辟一个空间
byte[] buf = new byte[1024];
// 读文件
int len = -1;
// buf是存储读取数据的缓冲区,
//in.read(buf)返回:读入缓冲区的字节总数,如果因为已经到达文件末尾而没有更多的数据,则返回-1
while ((len = in.read(buf)) != -1) {
//读取buf数组里面的数据 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String
String s = new String(buf, 0, len);
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
2.2.2字符流
字符流可以对流数据以一个字符的长度为单位来处理,并进行适当的字符编码转换处理,一般字符流都用来操作纯文本文件。
(1)字符流输出
Writer是一个字符输出流,但他是一个抽象类,所以必须有其子类FileWriter来实例化。
(2)字符流输入
Reader是一个字符输入流,但他是一个抽象类,所以必须有其子类FileReader来实例化。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class WriterDemo {
public static void main(String[] args) throws IOException {
FileWriter writer = null;
FileReader reader = null;
// 获取对象 FileWriter的构造函数,有true的代表直接在后面追加,没有代表覆盖前面的内容
writer = new FileWriter("D:/Hellow.txt", true);
// 直接输出字符串
writer.write("java c++");
writer.close();
//下面是读取
reader = new FileReader("D:/Hellow.txt");
char[] buf = new char[1024];
int len = 0;
while ((len = reader.read(buf)) != -1) {
String s = new String(buf, 0, len);
System.out.println(s);
}
reader.close();
}
}
2.2.3字节流与字符流的区别
- 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符。一次可能读取多个字节。
- 处理对象不同:字节流能处理所以类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
2.2.4过滤(处理)流DataOutputStream/DataInputStream
1.DataOutputStream
对于DataOutputStream必须给他传一个输出流对象:DataOutputStream(OutputStream out)
2.
DataInputStream
private static void ttt() throws IOException{
OutputStream out = new FileOutputStream("D:/Hellow.txt");
DataOutputStream data = new DataOutputStream(out);
data.writeInt(111);
data.writeBoolean(false);
data.writeInt(222);
data.writeBytes("saa");
data.flush();
data.close();
out.close();
}
private static void in() throws IOException{
InputStream in = new FileInputStream("D:/Hellow.txt");
DataInputStream data = new DataInputStream(in);
System.out.println(data.readInt());
System.out.println(data.readBoolean());
System.out.println(data.readInt());
System.out.println(data.readByte());
data.close();
}
挨着存进去,也要挨着一个个
2.2.5内存操作流 ByteArrayInputStream/ByteArrayOutputStream
String info = "hello Java";
InputStream in = new ByteArrayInputStream(info.getBytes());
OutputStream out = new ByteArrayOutputStream();
int temp=0;
while ((temp=in.read())!=-1) {
out.write(Character.toUpperCase((char)temp));//转换为大写
}
String str = out.toString();//取出内容
out.close();
in.close();
System.out.println(str);//HELLO JAVA
2.2.6缓冲流BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream
缓冲流的原理是将数据先缓冲起来,然后一起写入或读取出来,使用缓冲流读写文件非常高效,常用的有以下几种:BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream。
(1)BufferedReader和BufferedWriter
BufferedReader属于字符流,如果要使用BufferedReader就需要将字节流变成字符流,为了解决这一的问题,在Java中提供了一下两个转换类。
- 将输入的字节流变成字符流:InputStreamReader
- 将输出的字符流变成字节流:OutputStreamWriter
private static void writer() throws IOException{
//缓冲流写数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("D:/Hellow.txt")));
bw.write("Hellow");
bw.write("java");
bw.close();
}
private static void reader() throws IOException {
//创建对象 FileInputStream获得目标 InputStreamReader转为字符流
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream("D:/Hellow.txt")));
String str=null;
while ((str=br.readLine())!=null) {
System.out.println(str);
}
br.close();
}
(2)BufferedInputStream与BufferedOutputStream
使用 BufferedInputStream与BufferedOutputStream通常用来读取或写入影像数据,例如:影片、图片等。
下面是一个图片读写的例子:
private static void input_out() throws IOException{
BufferedInputStream in = new BufferedInputStream(new FileInputStream("D:\\test.png"));
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:\\test2.png"));
byte[] buf = new byte[1024];
int len=-1;
//读数据
while ((len=in.read(buf))!=-1) {
//写数据
out.write(buf, 0, len);
}
out.close();
in.close();
}
2.2.7对象序列化与反序列化Serializable
(1)序列化
所谓的对象序列化就是讲一个在内存中保存的对象变成一个二进制的数据进行传输,但并不是所有类的对象都可以进行序列化操作,如果一个对象需要被序列化,则对象所有的类必须实现Serializable接口
(2)返序列化
public class SerializableDemo {
public static void main(String[] args) throws IOException, IOException {
//创建对象
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/Hellow.txt"));
//需要序列化的对象
Person p = new Person();
p.setName("张学友");
p.setAge(20);
//将对象写进文件中
out.writeObject(p);
out.close();
}
}
//返序列化
class objectInputStream{
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:/Hellow.txt"));
Person p = (Person) in.readObject();
in.close();
System.out.println(p);
}
}
class Person implements Serializable{
String name;
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;
}
@Override
public String toString() {
return "姓名:"+name+" 年级:"+age;
}
}
(3)transient关键字
实际上在进行对象序列化时,序列化的是类中的属性,因为每个类的对象只有属性是不同的,但是如果现在有某个属性不希望被序列化,则可以使用transient关键字
private transient String name;
(4)序列化一组对象
通常在实际开发中肯定不只序列化一个对象,如果想要序列化多个对象,可以使用数组来解决。
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/Hellow.txt"));
//需要序列化的对象
Person p = new Person();
p.setName("张学友");
p.setAge(20);
Person p2 = new Person();
p.setName("刘德华");
p.setAge(25);
Person[] ps ={p,p2};
//将对象写进文件中
out.writeObject(ps);
out.close();
2.2.8打印刘 PrintStream
如果使用OutputStream输出数据,不是很方便,所以Java提供了打印流PrintStream,以后只要遇到打印文件,首选考虑使用PrintStream。public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream(new FileOutputStream("D:/Hellow.txt"));
ps.println('c');
ps.print("String");
ps.print(100);
ps.close();
FileReader fr = new FileReader("D:/Hellow.txt");
char[] c = new char[1024];
int emp=-1;
while ((emp=fr.read(c))!=-1) {
String s = new String(c, 0, emp);
System.out.println(s);
}
fr.close();
}
}
2.2.9 RandomAccessFile随机访问文件
RandomAccessFile可以随机读写文件,随机读写文件就是说可以任意访问文件的位置,
这是其他流锁不能操作 。RandomAccessFile类包含一个记录指针,用于标识当前流的读写位置,这个位置可以向前移动,也可以向后移动。RandomAccessFile包含两个方法来操作文件记录指针。
- long getFilePoint():记录文件指针的当前位置。
- void seek(long pos):将文件记录指针定位到pos位置。
//创建对象
RandomAccessFile raf = new RandomAccessFile("D:/Hell", "rw");
//写入byte数组
byte[] b = "hello java!".getBytes();
raf.write(b);
//设置偏移量 只有6以后的数据,就是java!
raf.seek(6);
System.out.println("pointer="+raf.getFilePointer());
byte[] b2 = "C++".getBytes();
raf.write(b2);
int len = -1;
byte[] buf = new byte[1024];
//将偏移量设置成第一个位置
raf.seek(0);
System.out.println("pointer="+raf.getFilePointer());
while ((len=raf.read(buf))!=-1) {
String s = new String(buf, 0, len);
System.out.println(s);
}
raf.close();