JavaIO流
File类
File类的理解
-
File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)
-
FiLe类声明在java.io包下。
-
File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用Io流来完成。
-
后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"。
File的构造器
-
File(String filePath)
-
File(string parentPath,string childPath)
-
File(File parentFile,string childPath)
路径的分类
- 相对路径:相较于某个路径下,指明的路径。
- 绝对路径:包含盘符在内的文件或文件目录的路径。
说明:IDEA中:
如果大家开发使用JUnit中的单元测试方法测试,相对路径即为当前Module下.如果大家使用main()测试,相对路径即为当前的Project下。
Eclipse中:
不管使用单元测试方法还是使用main()测试,相对路径都是当前的Project下。
路径分隔符
- windows和DOS系统默认使用"\"来表示
- UNIX和URL使用"/"来表示
File类的常用方法
File类的获取功能
- **public String getAbsolutePath():**获取绝对路径。
- public String getPath():获取路径。
- public String getName():获取名称。
- **public String getParent():**获取上层文件目录路径。若无,返回null。
- public long length():获取文件长度(即:字节数)。不能获取目录的长度。
- public long lastModified():获取最后一次的修改时间,毫秒值。
- public String[] list():获取指定目录下的所有文件或者文件目录的名称数组。
- public File[] listFiles():获取指定目录下的所有文件或者文件目录的File数组。
File类的重命名功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径
File类的判断功能
- **public boolean isDirectory():**判断是否是文件目录。
- **public boolean isFile():**判断是否是文件。
- **public boolean exists():**判断是否存在。
- public boolean canRead():判断是否可读。
- public boolean canWrite() :判断是否可写。
- public boolean isHidden():判断是否隐藏。
File类的创建功能
- **public boolean createNewFile():**创建文件。若文件存在,则不创建,返回false。
- public boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
- **public boolean mkdirs():**创建文件目录。如果上层文件目录不存在,一并创建注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下。
File类的删除功能
- **public boolean delete():**删除文件或者文件夹删除
- 注意事项:
Java中的删除不走回收站。
要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。
IO流
Java IO 原理
- I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
- Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。
- java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
- **输入input:**读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
- **输出output:**将程序(内存)数据输出到磁盘、光盘等存储设备中。
流的分类
- 按操作数据单位不同分为:字节流(8bit),字符流(16bit).
- 按数据流的流向不同分为:输入流,输出流。
- 按流的角色的不同分为:字节流,处理流。
(抽象基类) | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
- Java的Io流共涉及40多个类,实际上非常规则,都是从如下4个
抽象基类派生的。 - 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
IO流体系
字节流
FileReader
package com.zy.TestIO;
import org.junit.Test;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class TestFileReader {
// 说明点:
// 1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
// 2.异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
// 3.读入的文件一定要存在,否则就会报FiLeNotFoundException。
@Test
public void Test01(){
//创建流
FileReader fr = null;
try {
//1.实例化File对象,指明要操作的文件
File file = new File("src/com/zy/TestIO/hello.txt");
//2.具体的操作流
fr = new FileReader(file);
//3.创建接收
int data ;
//4.数据读入
//read()每次读入一个字符,如果到文件末尾,返回-1
while ((data=fr.read())!=-1)
{
//read()返回的是字符对应的ascii码
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//判断流存在,再关闭
if(fr!=null) {
try {
//关闭流
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void Test02(){
//创建流
FileReader fr = null;
try {
//1.实例化File对象,指明要操作的文件
File file = new File("src/com/zy/TestIO/hello.txt");
//2.具体的操作流
fr = new FileReader(file);
//3.创建接收字符数组,长度为5
char[] cbuffer = new char[5];
int len;
//4.数据读入
//read()每次读入字符数组长度,如果到文件末尾,返回-1
while ((len=fr.read(cbuffer))!=-1)
{
//方法1
// for(int i=0;i<len;i++)
// {
// System.out.print(cbuffer[i]);
// }
//方法2
String str =new String(cbuffer,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//判断流存在,再关闭
if(fr!=null) {
try {
//关闭流
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileWriter
package com.zy.TestIO;
import org.junit.Test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class TestFileWriter {
public static void main(String[] args) {
}
// 说明:
// 1.输出操作,对应的File可以不存在的。并不会报异常
// 2.File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
// File对应的硬盘中的文件如果存在:如果流使用的构造器是:Filewriter(file,false) / Filewriter(file)(默认为false):,对文件的进行覆盖
// 对原如果流使用的构造器是:Filewriter(file,true):不会对原有文件覆盖,而是在后面继续添加
@Test
public void Test01(){
FileWriter fw = null;
try {
//创建File的对象,指定操作
File file = new File("src/com/zy/TestIO/Hellot.txt");
//创建操作流
fw = new FileWriter(file);
//开始写入
fw.write("hello world\n");
fw.write("你好!");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if(fw!=null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
前两者结合
@Test
public void TestFileReaderFileWriter(){
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建读写的文件
File rfile = new File("src/com/zy/TestIO/hello.txt");
File wfile = new File("src/com/zy/TestIO/Hellot.txt");
//2.创建对应操作流
fr = new FileReader(rfile);
fw = new FileWriter(wfile);
//3.创建字符数组,开始读写
char[] cbuffer = new char[5];
int len;
while ((len = fr.read(cbuffer))!=-1)
{
fw.write(cbuffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
//方法1
// try {
// if(fw!=null)
// fw.close();
// } catch (IOException e) {
// e.printStackTrace();
// }finally {
// try {
// if(fr!=null)
// fr.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
//方法2,两者没有区别
try {
if(fw!=null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fr!=null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
不能用字符流实现图片视频的复制,要用字节流
FileInputStream FileOutputStream
package com.zy.TestIO;
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestFileInputStreamFileOutputStream {
//方法使用和字符流类似
// 测试FiLeInputstream和FileoutpuStream的使用*
// 结论:
// 1.对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
// 2.对于非文本文件(.jpg,.mp3 ,.mp4, .avi,.doc,.ppt,. ..),使用字节流处理
@Test
public void Test01(){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//使用字节流操作文本文件可能会出现乱码
//1.复制图片,开创建文件
File ipsFile = new File("src/com/zy/TestIO/bj.jpg");
File opsFile = new File("src/com/zy/TestIO/bj2.jpg");
//2.创建对应操作字节流
fis = new FileInputStream(ipsFile);
fos = new FileOutputStream(opsFile);
//3.创建字节数组
byte[] buffer = new byte[1024];
int len;
//4.开始复制
while ((len = fis.read(buffer))!=-1)
{
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//5.关闭流
try {
if(fos!=null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fis!=null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲流
BufferedInputStream,BufferedOutputStream
package com.zy.TestIO;
import org.junit.Test;
import java.io.*;
public class TestBuffered {
// 作用:提高流的读取、写入的速度
// 提高读写速度的原因:内部提供了一个缓冲区,大小为8192,bos.flush();刷新缓冲区,没存满就先输出,满了会自动调用
public static void CopyBuffered(String srcFile,String destFile){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//创建文件
File srcfile = new File(srcFile);
File destfile = new File(destFile);
//创建节点流
FileInputStream fis = new FileInputStream(srcfile);
FileOutputStream fos = new FileOutputStream(destfile);
//创建缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//创建字节数组,开始复制
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
//先关外面的,再关里面的
//不过缓冲流的关闭会自动关闭内部的流
if(bos!=null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis!= null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void Test01(){
long start = System.currentTimeMillis();
String srcFile = "E:\\QLDownload\\新世界\\新世界 第69集 蓝光(1080P).qlv";
String destFile = "E:\\视频\\xsj.qlv";
TestBuffered.CopyBuffered(srcFile,destFile);
long end = System.currentTimeMillis();
System.out.println("时间:"+(end-start));//时间:4119,没有用缓冲流的时间为6451
}
}
BufferedReader,BufferedWriter
使用方法和上面的相同,只是是字符流
读写的特殊方法
@Test
public void Test02(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建流
br = new BufferedReader(new FileReader(new File("src/com/zy/TestIO/hello.txt")));
bw = new BufferedWriter(new FileWriter(new File("src/com/zy/TestIO/hellot.txt")));
//方法一:
// char[] cb = new char[1024];
// int len;
// while((len=br.read(cb))!=-1){
// bw.write(cb,0,len);
// }
//方法二:
String data;
while ((data=br.readLine())!=null)//每次返回一行,结束返回null
{
// bw.write(data);//没有换行符,复制的内容会在一排
//1.
// bw.write(data+"\n");
//2.
bw.write(data);
bw.newLine();//相当于一个换行行符
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if(bw!=null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br!=null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
转换流
- 转换提供了在字符流和字节流之间的转换
- Java API 提供了两个转换流:
- InputStreamReader:将InputStream转换为Reader
- OutputStreamWriter:将Writer转换为OutputStream
- 这两个流属于字符流
- 字节流中的数据都是字符时,转换字符流操作更高效。
- 很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
- 解码:字节、字节数组—>字符数组、字符串
- 编码:字符数组、字符串—>字节、字节数组
package com.zy.TestIO;
import org.junit.Test;
import java.io.*;
public class TestInputStreamReader {
/**
* 结合使用,可以定义字符集,定义复制的文件的字符集
*/
@Test
public void Test01(){
InputStreamReader isr = null;
OutputStreamWriter osw = null;
try {
//1.创建流和操作的文件
isr = new InputStreamReader(new FileInputStream(new File("src/com/zy/TestIO/hello.txt")),"UTF-8");
osw = new OutputStreamWriter(new FileOutputStream(new File("src/com/zy/TestIO/hello_gdk.txt")),"gbk");
//2.读写操作
char[] cbuffer =new char[1024];
int len;
while ((len=isr.read(cbuffer))!=-1){
String str = new String(cbuffer,0,len);
System.out.println(str);
osw.write(cbuffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭流,外面关闭,内部一起
try {
if(osw!=null)
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(isr!=null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符编码
-
编码表的由来
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。 -
常见的编码表
- **ASCII:**美国标准信息交换码。
- 用一个字节的7位可以表示。
- **ISO8859-1:**拉丁码表。
- 欧洲码表用一个字节的8位表示。
- **GB2312:**中国的中文编码表。最多两个字节编码所有字符
- **GBK:**中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
- **Unicode:**国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示
- **UTF-8:**变长的编码方式,可用1-4个字节来表示一个字符。
- **ASCII:**美国标准信息交换码。
-
Unicode不完美,这里就有三个问题,一个是,我们已经知道,英文字母只用一个字节表示就够了,第二个问题是如何才能区别Unicode和IASClI?计算机怎么知道两个字节表示一个符号,而不是分别表示两个符号呢?第三个,如果和GBK等双字节编码方式一样,用最高位是1或O表示两个字节和一个字节,就少了很多值无法用于表示字符,不够表示所有字符。unicode在很长一段时间内无法推广,直到互联网的出现。
-
面向传输的众多UTF (UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。
-
Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-8和UTF-16。
其他类型流
标准的输入输出流
- System.in和System.out分别代表了系统标准的输入和输出设备
- 默认输入设备是:键盘,输出设备是:显示器
- System.in的类型是lnputStream
- System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream的子类
- 重定向:通过System类的setIn,setOut方法对默认设备进行改变。
- public static void setln(InputStream in)
- public static void setOut(PrintStream out)
package com.zy.TestIO;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Locale;
public class TestOtherIO {
public static void main(String[] args) {
BufferedReader br = null;
try {
//创建,要使用到缓冲流和转换流,测试System.in
br = new BufferedReader(new InputStreamReader(System.in));
//获取键盘输入的内容,exit结束
while (true){
System.out.println("输入:");
String str = br.readLine();
if(str.equalsIgnoreCase("exit")){
System.out.println("程序结束");
break;
}
String data = str.toUpperCase(Locale.ROOT);
System.out.println(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
try {
if(br!=null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
打印流
- 实现将基本数据类型的数据格式转化为字符串输出
- 打印流:PrintStream和PrintWriter
- 提供了一系列重载的print()和println()方法,用于多种数据类型的输出
- PrintStream和PrintWriter的输出不会抛出IOException异常
- PrintStream和PrintWriter有自动flush功能
- PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用PrintWriter 类。
- System.out返回的是PrintStream的实例
打印流就是可以将输出到页面的内容,自己定义一个文件,打印到那个文件中去
@Test
public void TestPrint(){
PrintStream ps = null;
try {
//创建文件输出流
FileOutputStream fos = new FileOutputStream(new File("src/com/zy/TestIO/print.txt"));
//创建打印流
ps = new PrintStream(fos,true);
//将标准输出改为文件
if(ps!=null)
{
System.setOut(ps);
}
//执行
for(int i =0;i<255;i++)
{
System.out.print((char) i);//输出AscII码字符
if(i%50==0)//每五十个换行
{
System.out.println();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
//关闭流
if(ps!=null)
ps.close();
}
}
数据流
- 为了方便地操作Java语言的基本数据类型和Strirjg的数据,可以使用数据流。
- 数据流有两个类:(用于读取和写出基本数据类型、String类的数据)
- DatalnputStream和 DataOutputStream
- 分别“套接”在 lnputStream和 OutputStream子类的流上
- DatalnputStream中的方法
boolean readBoolean()
byte readByte()
char readChar()
float readFloat()
double readDouble()
short readShort()
long readLong()
int readInt()
String readUTF()
void readFully(byte[] b) - DataOutputStream中的方法
将上述的方法的read改为相应的write即可。
@Test
public void TestDataOutputStream(){
DataOutputStream dos = null;
try {
//创建数据流,将内存中的数据写入文件
dos = new DataOutputStream(new FileOutputStream(new File("src/com/zy/TestIO/data.txt")));
//写入数据
dos.writeUTF("字符串");
dos.flush();//刷新缓冲,将上面内容保存到文件中
dos.writeInt(22);//int
dos.flush();
dos.writeBoolean(true);//boolean
dos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if(dos!=null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void TestDateInputStream(){
DataInputStream dis = null;
try {
//将基本类型从文件中输入出来
dis = new DataInputStream(new FileInputStream(new File("src/com/zy/TestIO/data.txt")));
//要按写入的顺序将它们输入
String str = dis.readUTF();
int i = dis.readInt();
boolean b = dis.readBoolean();
System.out.println("String:"+str+" int:"+i+" boolean:"+b);
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流
if(dis!=null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
用数据流存入文件的内容,只能用数据流再输出,不能直接查看
数据流只能操作基本数据类型和Strirjg的数据,要操作对象要使用对象流