IO流
File
1.File类是一个对象,代表一个文件或一个文件目录(即文件夹)
2.File类声明在java.io包下
3.如何创建File类的实例
4.相对路径:相较于某个路径下,指明的路径
绝对路径:包含盘符在内的文件或文件目录的路径
5.路径分隔符:windows:\ unix: \
File f1 = new File("hello.txt");//绝对路径 hello.txt
File f2 = new File("E:\\User\\hell1.txt");//相对路径 E:\User\hell1.txt
File f = new File("E:"+File.separatorChar+"User1"+File.pathSeparator+"h.txt");//E:\User1;h.txt
File f3 = new File("E:\\User","file");//E:\User\file
File f4 = new File(f3,"hello2o2.txt");//E:\User\file\hello2o2.txt
6.File中常用方法
File f1 = new File("hell1.txt");
System.out.println(f1.getAbsolutePath());//绝对路径 E:\User\\hell1.txt
System.out.println(f1.getPath());//路径 hell1.txt
System.out.println(f1.getName());//hell1.txt
System.out.println(f1.getParent());//上层文件目录 null
System.out.println(f1.length());//内容长度
System.out.println(new Date(f1.lastModified()));//最后一次修改时间,毫秒值 Thu Jan 01 08:00:00 CST 1970
File f2 = new File("E:\\User\\hell1.txt");
System.out.println(f2.getAbsolutePath());//绝对路径 E:\User\hell1.txt
System.out.println(f2.getPath());//路径 E:\User\hell1.txt
System.out.println(f2.getName());//hell1.txt
System.out.println(f2.getParent());//父类 E:\User
System.out.println(f2.length());//内容长度
System.out.println(f2.lastModified());//最近被修改时间 1586955653716
File f = new File("E:\\User\\test");//
//list()获取文件夹下的所有文件名
String[] list = f.list();
for(String s : list){
System.out.println(s);//test1 test2
}
File f1 = new File("E:\\User\\test");
//listFiles()获取文件夹下的所有文件路径名
File[] files = f1.listFiles();
for(File file : files){
System.out.println(file);//E:\User\test\test1 E:\User\test\test2
}
创建
/*
* 创建磁盘中对应的文件或文件目录
* 1.createNewFile() 创建文件,若文件存在,则不创建,返回false;反之,创建文件并返回true
* 2.delete()删除文件或文件夹。
* 3.mkdir()、 mkdirs() 文件夹的创建
* */
File f = new File("h.txt");
try {
//文件的创建和删除
System.out.println(f.createNewFile());
System.out.println(f.delete());
} catch (IOException e) {
e.printStackTrace();
}
//文件目录的创建,如下文件目录中只存在E:\User
File f1 = new File("E:\\User\\hell\\test1");
//1.mkdir()文件上层目录不存在,则不会创建文件;如上由于hell文件目录不存在,则创建文件目录失败
System.out.println(f1.mkdir());
File f2 = new File("E:\\User\\hell\\test2");
//2.mkdirs()文件上层目录不存在,则会创建上层目录,如上hell文件目录不存在,但仍然会创建出该文件目录
System.out.println(f1.mkdirs());
//删除文件夹时,该文件夹下没有内容时可以删除成功,否则删除失败
注:File类中涉及到文件和文件目录的操作,并未涉及写入或读取文件的内容操作,此操作需要借助IO流实现;File类对象作为参数传递到流的构造器中,指明读取或写入的“终点”
IO流
IO流(程序角度分析流) 流的分类节点流(即文件流,访问文件的操作)
字符流:对文件进行读取操作
/*
* 文件的相对路径:
* idea中main:相对于Project而言,JUnitTest中相对当前moudle;eclipse中相对路径相同
*
* */
public static void main(String[] args) {
File f = new File("\\Moudle\\hello.txt");//需要添加moudle的路径
System.out.println(f.getAbsolutePath());//E:\User\vv\Moudle\hello.txt
}
@Test
public void test() throws Exception {
//1.指明要操作的文件
File f = new File("hello.txt");
System.out.println(f.getAbsolutePath()); //E:\User\vv\Moudle\hello.txt
//2.获得文件的输入流
FileReader fr = new FileReader(f);
int data ;
while((data = fr.read()) != -1){//判断是否能读取到字符,达到文件末尾时返回-1
System.out.print((char)data+"\t");//(char)fr.read()将字节码转换成字符
}
fr.close();
}
//为保证IO流可以正常关闭,应该使用try-catch-finally而不是throws异常
@Test
public void test() {
//1.指明要操作的文件
File f = new File("hello.txt");
System.out.println(f.getAbsolutePath()); //E:\User\vv\Moudle\hello.txt
FileReader fr = null;
try {
//2.获得文件的输入流
fr = new FileReader(f);
int data ;
while((data = fr.read()) != -1){//判断是否能读取到字符,达到文件末尾时返回-1
System.out.print((char)data+"\t");//(char)fr.read()将字节码转换成字符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭文件输入流
if(fr != null)
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//同时读入的文件若不存在,则java.io.FileNotFoundException:
read()的各种重载方法读取数据
//1.空参read()
int data ;
while((data = fr.read()) != -1){//判断是否能读取到字符,达到文件末尾时返回-1
System.out.print((char)data+"\t");//(char)fr.read()将字节码转换成字符
}
//2.read(char[] c)
char[] data = new char[5];//此时的数组大小固定,
int len ;
while((len = fr.read(data) )!= -1)
// //错误写法,每次读取的都是data的固定长度字符,
// for (int i = 0; i < data.length; i++) {
// System.out.print(data[i]);//hello123lo 文件中是hello123;第一次hello,第二次时,将hello替换成123lo
// }
//正确写法,每次遍历读取到的长度len
for (int i = 0; i < len; i++) {
System.out.print(data[i]);//hello123
}
//3.read(char[] c,int offset,int count)
//方式二:
// //错误写法:原因和上述错误一相同
// String str = new String(data);
// System.out.print(str);//hello123lo
//正确写法
String str1 = new String(data,0,len);
System.out.print(str1);//hello123
字符流:对文件进行输出操作
/*
* 从内存中写入数据到硬盘文件里
* 说明:在输出操作中在输出操作中
* 1.文件不存在时,不会报异常,而是会自动创建该文件
* 2.文件存在时,new FileWriter(f,true);表示在原有文件后添加数据;
* new FileWriter(f,false);/new FileWriter(f);表示覆盖原有数据,重新写入
* */
@Test
public void test01() throws IOException {
//1.指明输出的文件
File f = new File("Hi.txt");
//2.创建FileWriter用于文件输出
FileWriter fw = new FileWriter(f);
//3.输出内容
fw.write("hello\n");
fw.write("world");
fw.close();
}
同时进行字符的输入和输出操作
@Test
public void test02() {
File f1 = new File("Hi.txt");
File f2 = new File("HiHi.txt");
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader(f1);
fw = new FileWriter(f2);
int data;
char[] c = new char[5];
while((data = fr.read()) != -1){//data = fr.read(c)每次read字符的个数为c
fw.write(c,0,data);
}
}catch (IOException e) {
e.printStackTrace();
}
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
读取时文本文件(txt、java、c++)使用字符流处理,对于非文本文件(图片、音频、doc、ppt等)使用字节流处理;复制时,文本文件可以通过字节流处理,但非文本文件不能使用字符流处理
缓冲流:(字节)对文件的读取和写入速度提高
@Test
public void test01() {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.指明要操作的文件
File f1 = new File("2.PNG");
File f2 = new File("4.PNG");
//2.获得文件的输入和输出流
//(1)造节点流
fis = new FileInputStream(f1);
fos = new FileOutputStream(f2);
//(2)造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.对文件进行复制
int b;
byte[] bytes = new byte[1024];
while((b = bis.read(bytes)) != -1){//读取的bytes
bos.write(bytes,0,b);
bos.flush();//刷新缓冲区
}
}catch(java.io.IOException e){
e.printStackTrace();
}finally{
//4.关流(缓冲流close操作中,内部已经对节点流close过,不需要再进行关闭节点流)
if(bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用缓冲流(字符)输出数据时,有两种方式:char[] 和String
@Test
public void test01(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
br = new BufferedReader(new FileReader(new File("1.txt")));
bw = new BufferedWriter(new FileWriter(new File("2.txt")));
// //方法一:使用char[]
// int i;
// char[] c = new char[1024];
// while ((i = br.read(c)) != -1){
// bw.write(c,0,i);
// }
//方法二:使用String
String data;
while((data = br.readLine()) != null) {//按行读取
String str = new String(data);
//换行两种方式
//一:
bw.write(str + "\n");
//二:
bw.write(str);//将String对象中的数据写入文件,但此方法没有进行换行
bw.newLine();//进行换行处理
}
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
对图片加密操作
@Test
public void test01(){
try {
FileInputStream fis = new FileInputStream("5.PNG");
FileOutputStream fos = new FileOutputStream("6.PNG");
int b ;
byte[] bytes = new byte[10];
while ((b = fis.read(bytes)) != -1){
// //字节数组进行修改
// //错误:
// for(byte b1 : bytes){
// b1 = (byte)(b ^ 5);//次数是对新的b1变量修改了,但bytes并没有改变
// }
//准确
for (int i = 0; i < b; i++) {//循环的应该是每次获得的长度
bytes[i] = (byte)(bytes[i] ^ 5);
}
fos.write(bytes,0,b);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
转换流
1.InputStreamReader:将字节的输入流转换为字符的输入流
OutputStreamWriter:将字符的输出流转换为字节的输出流
2.作用:提供字节流和字符流之间的转换
3.解码:字节、字节数组----》字符数组、字符串
编码:字符数组、字符串----》字节、字节数组
4.字符集
ASCII、ISO8859-1、GB2312、GBK、Unicode、utf-8(每8位传输)
ANSI编码:即平台默认编码;如:英文操作系统ISO-8859-1,中文系GBK
转换流
实现字节流输入流---》字符流输入流
@Test
public void test01() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
//字节流---》字符流
InputStreamReader isr = new InputStreamReader(fis);//默认使用该工具的字符集
InputStreamReader isr1 = new InputStreamReader(fis,"gbk");//自定义字符集
int i;
char[] c = new char[10];
while((i = isr1.read(c)) != -1){
System.out.println(c);
}
isr.close();
}
实现字节流输入流---》字符流输入流 和 字符输出流-----》字节输出流
@Test
public void test02() throws IOException {
FileInputStream fis = new FileInputStream("1.txt");
FileOutputStream fos = new FileOutputStream("3.txt");
InputStreamReader isr = new InputStreamReader(fis,"utf-8");//使用utf-8获得输入的字符流
OutputStreamWriter osr = new OutputStreamWriter(fos,"gbk");//使用gbk输出字节流
int i;
char[] c = new char[10];
while((i = isr.read(c)) != -1){
osr.write(c,0,i);
}
osr.close();
isr.close();
fos.close();
fis.close();
}
获取文本上每个字符出现的次数,并进行相加
@Test
public void test01() throws IOException {
//1.读取的文件
FileReader fr = new FileReader("1.txt");
int r;
char[] c = new char[3];
//2.将读取文件的字符和每个字符出现的次数存储在HashMap中
HashMap<Character,Integer> hashMap = new HashMap<>();
while((r = fr.read(c)) != -1){
for (int i = 0; i < r; i++) {//循环时应该根据读取到的实际长度判断
//3.判断该HashMap是否包含该字符,若包含,则放入HashMap中,出现次数+1,;不包含,则放入HashMap中,出现数为1
if(hashMap.containsKey(c[i])){
hashMap.put(c[i],hashMap.get(c[i])+1);
}else{
hashMap.put(c[i],1);
}
}
}
fr.close();//必须将写入流关闭,否则无法写出数据
//4.将获取的字符和出现的字符次数重新存入文件中
FileWriter fw = new FileWriter("char.txt");
Iterator<Map.Entry<Character, Integer>> iterator = hashMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<Character, Integer> next = iterator.next();
System.out.println(next.getKey() + "......" + next.getValue());
String str = new String(next.getKey() + "......" + next.getValue());
fw.write(str);
}
fw.close();
}
标准输入输出流
System.in(默认从键盘输入) System.out(默认从控制台输出)
打印流
PrintStream PrintWriter
数据流:用于读取或写入基本数据类型、String类的变量或字符串
DataInputStream DataOutputStream
对象流ObjectOutputStream、ObjectInputStream
1.作用:用于存储和读取基本数据类型或对象的处理流,主要是可以进行序列化
2.序列化:即将内存中的java对象保存到磁盘中或通过网络传输出去(保存),好处在于可以将任何实现了Serializable接口的对象转化为字节数据,使其在保存和输出时可以被还原
某个对象要实现序列化机制,则必须实现Serializable或Externalizable接口,否则,会抛出NotSerializableException异常
3.反序列化:将磁盘中的文件对象还原为内存中的一个java对象(读取)
ObjectOutputStream、ObjectInputStream不能序列化static和transient修饰的成员变量
4.凡是Serializable接口的类都有一个表示序列化版本标识符的静态变量,用来表明类的不同版本间的兼容性;若没有这个静态变量,则类的实例变量进行修改时,serialVersionUID的值可能发生变化
即对象实现序列化的条件:
(1)需要实现接口
(2)对当前类提供一个全局常量serialVersionUID
(3)出来当前类需要SerialVersionUID接口外,还必须保证其内部所有属性也必须是可序列化的(默认情况下,基本数据类型、String就可序列化)
例题:对象流对字符串进行序列化和反序列操作
@Test
public void test01() throws IOException {
//序列化(OutputStream输出流,没有文件会自动创建)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("2.dat"));
oos.writeObject("hhhh好的");
oos.close();
}
@Test
public void test02() throws IOException, ClassNotFoundException {
//反序列化(InputStream)
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("1.dat"));
Object o = ois.readObject();
String s = (String) o;
System.out.println(s);
ois.close();
}
serialVersionUID作用举例
@Test
public void test01() throws IOException {
//1.对Person对象进行序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person1.txt"));
//没有对Person序列化时,java.io.NotSerializableException: com.vv.file.test.Person
oos.writeObject(new Person("xiaoli",14));
oos.close();
}
@Test
public void test02() throws IOException, ClassNotFoundException {
//1.对Person对象进行反序列化
//java.io.InvalidClassException
//在未对该类赋予序列化常量,并对Person序列化后,又对该类修改,再执行反序列化时,没有找到该类
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person1.txt"));
Object o = ois.readObject();
Person p = (Person) o;
System.out.println(p);
ois.close();
}
public class Person implements Serializable{
public static final long serialVersionUID = 123456789L;
public Account account;//Account类也必须是可序列化的
}
public class Account implements Serializable{
public static final long serialVersionUID = 456789321L;
}
RandomAccessFile
1.RandomAccessFile直接继承与java.lang.Object类,实现了DataInput和DataOutput
2.既可以作为输入流,也可以作为输出流
3.作为输出流时,写出的文件若不存在,则创建;若存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
//获取操作的文件,并指定操作的方式可读和可写
RandomAccessFile rsf2 = new RandomAccessFile("1.txt","rw");
// //1."1.txt"中原内容abcdef 写入后ok1def
// rsf2.write("ok1".getBytes());
//// rsf2.close();
//
// //2.在指定位置写入
// rsf2.seek(3);//原内容ok1def 写入后ok1ok1
// rsf2.write("ok1".getBytes());
//// rsf2.close();
//3.在指定位置写入,但不会覆盖原有数据 元数据ok1mnp 插入后数据ok1hhhmnp
StringBuilder sb = new StringBuilder((int) new File("1.txt").length());//指定文件的长度
int i;
byte[] b = new byte[2];
rsf2.seek(3);//保存指针3后的数据到StringBuilder中
while ((i = rsf2.read(b)) != -1){
sb.append(new String(b, 0, i));
}
rsf2.seek(3);//指定位置插入
rsf2.write("hhh".getBytes());//指定位置插入的数据
System.out.println(rsf2.getFilePointer());
rsf2.write(sb.toString().getBytes());//将插入后的文件中追加刚才保存的数据
rsf2.close();
java NIO支持面向缓冲区的(IO是面向流的)即基于通道的IO操作
分为量部分:1.针对标准输入输出的NIO 2.针对网络编程的NIO
java.nio.channels.Channel
jdk7出现Path、Paths、Files