1. 主要类
  2. java知识点拾遗(IO流-1)_释放资源

  3. File类
  • 名称分隔符
path1="d:/temp/test.txt";
path2="d:"+File.separator+"temp"+File.separator+"test.txt";

//1、构建File对象
File src = new File(path);
System.out.println(src.length());

//2、构建File对象
src = new File("D:/java300/IO_study01","IO.png");
src = new File("D:/java300/","IO_study01/IO.png");
System.out.println(src.length());

//3、构建File对象
src = new File(new File("D:/java300/IO_study01"),"IO.png");
System.out.println(src.length());
  • 路径基本信息
//用户目录
System.out.println(System.getProperty("user.dir"));
//取得绝对路径
src = new File("IO.png");
System.out.println(src.getAbsolutePath());

File src = new File("IO_study01/IO.png");

//基本信息
System.out.println("名称:"+src.getName());
System.out.println("路径:"+src.getPath());
System.out.println("绝对路径:"+src.getAbsolutePath());
System.out.println("父路径:"+src.getParent());
System.out.println("父对象:"+src.getParentFile().getName());

//文件状态
src = new File("xxx");
if(null == src || !src.exists()) {
System.out.println("文件不存在");
}else {
if(src.isFile()) {
System.out.println("文件操作");
}else { //src.isDirectory()
System.out.println("文件夹操作");
}
}

//获取文件的长度字节数(文件夹返回0)
File src = new File("D:/java300/IO_study01/IO.png");
System.out.println("长度:"+ src.length());

//文件操作
//createNewFile() : 不存在才创建,存在创建失败,只能创建文件
//delete():删除已经存在的文件
//操作系统的设备名不能作为文件名创建
File src = new File("D:/java300/IO_study01/io.txt");
boolean flag =src.createNewFile();
System.out.println(flag);
flag = src.delete();
System.out.println(flag);
  • 创建目录
//1、mkdir() : 确保上级目录存在,不存在创建失败
//2、mkdirs(): 上级目录可以不存在,不存在一同来创建

File dir = new File("D:/java300/IO_study01/dir/test");
//创建目录 mkdirs()
boolean flag = dir.mkdirs();
System.out.println(flag);
//创建目录 mkdir()
dir = new File("D:/java300/IO_study01/dir/test2");
flag = dir.mkdirs();
System.out.println(flag);
  • 列出目录信息
File dir = new File("D:/java300/IO_study01");

//下级名称 list
String[] subNames = dir.list();
for(String s:subNames) {
System.out.println(s);
}

//下级对象 listFiles()
File[] subFiles = dir.listFiles();
for(File s:subFiles) {
System.out.println(s.getAbsolutePath());
}

//所有盘符
File[] roots = dir.listRoots();
for(File r:roots) {
System.out.println(r.getAbsolutePath());
}
  • 统计目录的大小(Byte)
public class Test {
public static void main(String[] args) {
File src = new File("D:\\java300\\IO_study01");
count(src);
System.out.println(len);
}
private static long len =0;
public static void count(File src) {
//获取大小
if(null!=src && src.exists()) {
if(src.isFile()) { //大小
len+=src.length();
}else { //子孙级
for(File s:src.listFiles()) {
count(s);
}
}
}
}
}
  1. 字符编码
    Java字符使用16位的双字节存储。

字符集

说明

US-ASCII

ASCII编码

ISO-8859-1

Latin-1 拉丁字符,包含中文,日文等

UTF-8

变长Unicode字符(1-3字节),英文字符占1个字节,中文字符占3个字节。

UTF-16BE

定长Unicode字符(2字节),Gig-Ending编码:高字节低地址

UTF-16LE

定长Unicode字符(2字节),Little-Ending编码:低字节低地址

UTF_16

文件的开头指明BE/LE编码方式,即BOM(Byte Order Mark):“FE FF”表示BE编码,“FF FE”表示LE编码

这里ANSI指系统默认的字符集——windows中文环境下默认字符集是GBK。

  • 字符编码
String english = "abc";
String chinese = "将进酒";

byte[] data1 = english.getBytes();
System.out.println("英文\"" + english + "\"的长度:" + data1.length);
byte[] data2 = english.getBytes("GBK");
System.out.println("英文\"" + english + "\"的长度:" + data2.length);

byte[] data3 = chinese.getBytes(); // 默认getBytes("UTF8"),工程字符集,字符集名称大小写均可
System.out.println("中文\"" + chinese + "\"的长度:" + data3.length);
byte[] data4 = chinese.getBytes("GBK");
System.out.println("中文\"" + chinese + "\"的长度:" + data4.length);
  • 字符解码
    String–>byte[]:编码
    byte[] -->String:解码
String str1 = "米国USA";
byte[] data = str1.getBytes();

String str2 = new String(data, 0, data.length, "gbk");
System.out.println(str2);
String str3 = new String(data, "utf8");
System.out.println(str3);
  • 乱码的原因
  • 字节数不够
  • 编码字符集不匹配
  • 中文字符集
    cp936<gb2312<bgk
  1. IO流
  2. java知识点拾遗(IO流-1)_控制流_02

  • 字节流
    InputStream/OutputStream
  • 字符流
    Reader/Writer
  • 读操作步骤(概念)
//1、创建源
File src = new File("abc.txt");
//2、选择流
try {
InputStream is =new FileInputStream(src);
//3、操作 (读取)
int data1 = is.read(); //第一个数据s
int data2 = is.read(); //第二个数据x
int data3 = is.read(); //第三个数据t
int data4 = is.read(); //????不是数据,文件的末尾返回-1
System.out.println((char)data1);
System.out.println((char)data2);
System.out.println((char)data3);
System.out.println(data4);
//4、释放资源
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
  • 操作步骤

字节读

//1、创建源
File src = new File("abc.txt");
//2、选择流
InputStream is =null;
try {
is =new FileInputStream(src);
//3、操作 (读取)
int temp ;
while((temp=is.read())!=-1) { //一个字节一个字节地读
System.out.println((char)temp);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、释放资源
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

块读

//1、创建源
File src = new File("abc.txt");
//2、选择流
InputStream is =null;
try {
is =new FileInputStream(src);
//3、操作 (分段读取)
byte[] flush = new byte[1024*10]; //缓冲容器
int len = -1; //接收长度
while((len=is.read(flush))!=-1) {
//字节数组-->字符串 (解码)
String str = new String(flush,0,len); //String str = new String(flush, "utf8");
System.out.print(str);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、释放资源
try {
if(null!=is) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
  • 写操作
//1、创建源
File dest = new File("dest.txt");
//2、选择流
OutputStream os =null;
try {
os = new FileOutputStream(dest,true); //true表示追加写入
//3、操作(写出)
String msg ="IO is so easy\r\n";
byte[] datas =msg.getBytes(); // 字符串-->字节数组(编码,默认字符集)
//byte[] datas = msg.getBytes("utf8"); 按照utf8字符集编码
os.write(datas,0,datas.length); //或者out.write(datas);
os.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally{
//4、释放资源
try {
if (null != os) {
os.close();
}
} catch (Exception e) {
}
}
  • 释放资源
    先打开的后关闭,后打开的先关闭。
    可以利用Closeable接口封装释放资源的动作。
public static void close(Closeable... ios) {
for(Closeable io:ios) {
try {
if(null!=io) {
io.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

或者可以利用try …with…resources自动资源释放(JDK7之后)

try(is;os) { //<----------is和os自动释放     
或者
try( InputStream is=new FileInputStream(src);
OutputStream os=new FileOutputStream(dest);){

......
......
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
  • 纯文本处理
    FileReader/FileWriter(内置解决字符编解码问题)
    append()返回Writer,故可以实现链式引用。

块读

//1、创建源
File src = new File("abc.txt");
//2、选择流
Reader reader =null;
try {
reader =new FileReader(src);
//3、操作 (分段读取)
char[] flush = new char[1024]; //缓冲容器,注意是字符数组不是字节数组
int len = -1; //接收长度
while((len=reader.read(flush))!=-1) {
//字符数组-->字符串,解码无需指定字符集(系统已经处理好了)
String str = new String(flush,0,len);
System.out.println(str);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、释放资源
try {
if(null!=reader) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

块写

//1、创建源
File dest = new File("dest.txt");
//2、选择流
Writer writer =null;
try {
writer = new FileWriter(dest);
//3、操作(写出)
//写法一
//String msg ="I love you baby\r\n你知道我在等你吗";
//char[] datas =msg.toCharArray(); // 字符串-->字符数组(不存在编码问题)
//writer.write(datas,0,datas.length);
写法二
String msg ="I love you baby\r\n你知道我在等你吗";
writer.write(msg);
writer.write("add");
writer.flush();

//写法三
//writer.append("I love you baby\r\n").append("你知道我在等你吗");
//writer.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally{
//4、释放资源
try {
if (null != writer) {
writer.close();
}
} catch (Exception e) {
}
}
  • 字节数组流
    ByteArrayInputStream&ByteArrayOutputStream,在内存中,Java可以直接访问,无需关闭。
  • 处理流
    使用了装饰模式。
  • java知识点拾遗(IO流-1)_释放资源_03

  • 装饰器类包裹/包装基本类。接口方法(产生多态行为)从装饰器类向基本类方向层层调用,然后由内层的基本类向外部的包装类层层返回。抽象类实现接口,但主要是要提供公共属性。
  1. 流的缓冲
  • 提供缓冲的装饰流类可以提高IO性能。
  • 控制流的基础是节点流,底层不能没有节点流。
  • 释放外层装饰器流类的对象,则内层的基本流类对象资源会自动释放。释放是从里到外依次释放。

这里节点流是基本IO流类,而控制流是装饰器IO流类。装饰器IO流类提供流的缓冲提升IO效能。控制流类包装节点流类——装饰器类包装基本类。
示例如下:

File src = new File("abc.txt");
...
is=new BufferedInputStream(new FileInputStream(src));
装饰器类 基本类
控制流类 节点流类
提升IO效能
后释放(手动) 先释放(自动)
-------------------------------------------------------------------
File dest = new File("dest.txt");
...
os =new BufferedOutputStream( new FileOutputStream(dest));
  1. 字符输入输出加入缓冲流
  • 读入
//1、创建源
File src = new File("abc.txt");
//2、选择流
BufferedReader reader =null;
try {
reader =new BufferedReader(new FileReader(src));
//3、操作 (分段读取)
String line =null;
while((line=reader.readLine())!=null) {
//字符数组-->字符串
System.out.println(line);
}

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//4、释放资源
try {
if(null!=reader) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
  • 写出
//1、创建源
File dest = new File("dest.txt");
//2、选择流
BufferedWriter writer =null;
try {
writer = new BufferedWriter(new FileWriter(dest));
//3、操作(写出)
writer.append("I love you baby");
writer.newLine(); //输出一个\r\n
writer.append("偏偏喜欢你");
writer.flush();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally{
//4、释放资源
try {
if (null != writer) {
writer.close();
}
} catch (Exception e) {
}
}
  1. 转换流
    CharactorStreams—>InputStreamReader/OutputStreamWriter—>ByteStreams

InputStreamReader/OutputStreamWriter能将字节流转换为字符流,并且能为字节流指定字符集。

InputStreamReader对应解码;OutputStreamWriter对应编码。

  • 将字节流转换成字符流
//操作System.in 和System.out
try(BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer =new BufferedWriter(new OutputStreamWriter(System.out));){
//循环获取键盘的输入(exit退出),输出此内容
String msg ="";
while(!msg.equals("exit")) {
msg = reader.readLine(); //循环读取
writer.write(msg); //循环写出
writer.newLine();
writer.flush(); //强制刷新。不强制刷新,在缓存未满时不输出,卡在上一步。
}
}catch(IOException e) {
System.out.println("操作异常");
}
  • 处理指定字符集
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;

public class ConvertTest {
public static void main(String[] args) {
try(BufferedReader reader =
new BufferedReader(
new InputStreamReader(
new URL("http://www.baidu.com").openStream(),"UTF-8"));
BufferedWriter writer =
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("baidu.html"),"UTF-8"));){
//3、操作 (读取)
String msg ;
while((msg=reader.readLine())!=null) {
//System.out.println(msg);
writer.write(msg); //如果字符集不统一将出现乱码
writer.newLine();
}
writer.flush();
}catch(IOException e) {
System.out.println("操作异常");
}
}
}
  1. 数据流
    DataInputStream/DataOutputStream保存了数据及其类型。
//写出
ByteArrayOutputStream baos =new ByteArrayOutputStream();
DataOutputStream dos =new DataOutputStream(new BufferedOutputStream(baos));
//操作数据类型 + 数据
dos.writeUTF("白日依山尽");
dos.writeInt(18);
dos.writeBoolean(false);
dos.writeChar('a');
dos.flush();
byte[] datas =baos.toByteArray();
System.out.println(datas.length);
//读取
DataInputStream dis =new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(datas)));
//顺序与写出一致
String msg = dis.readUTF();
int age = dis.readInt();
boolean flag = dis.readBoolean();
char ch = dis.readChar();
System.out.println(flag);