Java IO 编程
提供了大量的Input和output 方法。
一个类File 和五个接口四个抽象类
File 类
唯一一个与文件本身操作的类,这个类可以进行操作文件路径的指派,可以创建或者删除文件,还可以获取文件的相关内容信息。
No | 方法名称 | 类型 | |
---|---|---|---|
01 | File(String pathname) | 构造 | 设置要操作文件的完整路径 |
02 | File(File parent, String child) | 构造 | 设置要操作文件的父目录和文件 |
03 | public boolean createNewFile() throws IOException | 方法 | 创建文件 |
04 | public boolean exists() | 方法 | 判断文件是否存在 |
05 | public boolean delete() | 方法 | 文件删除 |
文件的操作
public class TestDemo {
public static void main(String[] args) throws IOException {
File file = new File("D:"+File.separator+"demo.txt");
if (file.exists()){
file.delete();
System.out.println("文件已删除");
}else{
file.createNewFile();
System.out.println("文件已经添加");
}
}
}
问题1:当前文件进行了磁盘文件的操作,添加删除文件有延迟。
问题2: java 本身是跨平台的编程模式,这种情况必须考虑各个系统的路径问题
* windows 系统的路径分隔符 ”\“
* Unix, 类Unix(Linux\Macos\AIX) 路径分隔符为“/”
但是在编写路径分隔符的时候,如果每次都使用大量的“\\” 或者“//” 进行转义处理。
public static final String separator
正确的编写方法
File file = new File("D:"+File.separator+"demo.txt");
在以后的编写代码中,所有的路径分隔符尽量都通过常量来进行定义
文件目录的操作
当前的程序是直接在“D” 盘的根目录中创建,但是很多时候,文件路径并不存在,
执行程序的时候会出现以下问题,系统找不到指定路径。
如果想要进行目录的创建,需要使用File 类的以下几种方法
No | 方法名称 | 类型 | |
---|---|---|---|
01 | public boolean mkdir() | method | 只创建单级目录 |
02 | public boolean mkdirs() | method | 创建多级目录 |
03 | public String getParent() | method | 获取父路径的信息(String) |
04 | public File getParentFile() | method | 获取父路径的File实例 |
范例:进行父目录的创建。
public class TestDemo {
public static void main(String[] args) throws IOException {
File file = new File("D:"+File.separator+"demo"+File.separator+"demo.txt");
if(!file.getParentFile().exists()){//判断父目录是否存在
file.getParentFile().mkdirs();//创建所有的父路径
}
if (file.exists()){
file.delete();
System.out.println("文件已删除");
}else{
file.createNewFile();
System.out.println("文件已经添加");
}
}
}
多线程访问时,重复判断父目录是否存在浪费系统性能,修改程序父目录判断操作只执行一次
考虑使用静态代码块,静态代码优先于主程序执行
public class TestDemo {
private static File file = new File("D:"+File.separator+"dem"+File.separator+"demo.txt");
static {//只执行一次,
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();//创建所有的父路径
}
}
public static void main(String[] args) throws IOException {
if (file.exists()){
file.delete();
System.out.println("文件已删除");
}else{
file.createNewFile();
System.out.println("文件已经添加");
}
}
}
获取文件目录信息
No | 方法名称 | 类型 | |
---|---|---|---|
01 | public boolean canExecute() | method | 可执行 |
02 | public boolean canRead() | method | 可读 |
03 | public boolean canWrite() | method | 可写 |
04 | public File getAbsoluteFile() | method | 文件的绝对路径实例 |
05 | public String getName() | method | 获取文件或目录名 |
06 | public boolean isDirectory() | method | 是目录 |
07 | public boolean isFile() | method | 是文件 |
07 | public long lastModified() | method | 文件最后修改时间 |
08 | public long length() | method | 文件大小,返回 bytes, |
09 | public boolean isHidden() | method | 文件是否隐藏 |
范例:
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;
/**
* Created by 逸足天涯
* on 3/21/2020.
*/
public class TestDemo2 {
private static File file = new File("D:"+File.separator+"dem"+File.separator+"demo.txt");
static {//只执行一次,
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();//创建所有的父路径
}
}
public static void main(String[] args) throws IOException {
if (file.exists()){
System.out.println("文件是否能执行?"+file.canExecute());
System.out.println("文件是否能读?"+file.canRead());
System.out.println("文件是否能写?"+file.canWrite());
System.out.println("文件的绝对路径"+file.getAbsoluteFile());
System.out.println("文件名称"+file.getName());
System.out.println("文件是否是目录"+file.isDirectory());
System.out.println("文件是否为文件"+file.isFile());
System.out.println("文件的最后修改日期"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(file.lastModified())));
System.out.println("文件长度"+file.length());
}
}
}
public class TestDemo3 {
private static File file = new File("D:"+File.separator+"cn_windows_10_consumer_edition_version_1809_updated_sept_2018_x64_dvd_f7b9c8a9.iso");
public static void main(String[] args) throws IOException {
System.out.println(String.format("%5.2f",(file.length()/(double)1024/1024/1024))+"G");
}
}
获取目录中所有子文件和目录
No | 方法名称 | 类型 | |
---|---|---|---|
01 | public String[] list() | method | 描述子路径信息(不包含父目录) |
02 | public File[] listFiles() | method | 列出所有路径信息,(File 对象数组) |
public class TestDemo4 {
public static void main(String[] args) {
File file = new File("D:");
String[] list = file.list();
List<String> strings = Arrays.asList(list);
strings.forEach(str-> System.out.println(str));
}
}
输出结果:
$360Section
$RECYCLE.BIN
01尚硅谷SpringBoot核心技术篇
360Downloads
360安全浏览器下载
360极速浏览器下载
360驱动大师目录
app
BaiduNetdiskDownload
bootstrap4.zip
cn_windows_10_consumer_edition_version_1809_updated_sept_2018_x64_dvd_f7b9c8a9.iso
dem
downloads
Office_Professional_Plus_2016_x64_CN_2019.03.iso
Program Files (x86)
restful-crud-实验
springboot_001
ssmbuild
Struts 2+Hibernate+MyBatis+Spring 网站开发案例课堂
System Volume Information
WindowsImageBackup
中文年度加强版.rar
我的文档
新桌面
迅雷下载
结论: 获得子路径下所有的目录或者文件的名字。
public class TestDemo4 {
public static void main(String[] args) {
File file = new File("D:");
File[] list = file.listFiles();
Arrays.asList(list).forEach(str-> System.out.println(str));
}
}
输出结果:
D:$360RTLOG$
D:$360Section
D:$RECYCLE.BIN
D:\01尚硅谷SpringBoot核心技术篇
D:\360Downloads
D:\360安全浏览器下载
D:\360极速浏览器下载
D:\360驱动大师目录
D:\app
D:\BaiduNetdiskDownload
D:\bootstrap4.zip
D:\cn_windows_10_consumer_edition_version_1809_updated_sept_2018_x64_dvd_f7b9c8a9.iso
D:\dem
D:\downloads
D:\Office_Professional_Plus_2016_x64_CN_2019.03.iso
D:\Program Files (x86)
D:\restful-crud-实验
D:\springboot_001
D:\ssmbuild
D:\Struts 2+Hibernate+MyBatis+Spring 网站开发案例课堂
D:\System Volume Information
D:\WindowsImageBackup
D:\中文年度加强版.rar
D:\我的文档
D:\新桌面
D:\迅雷下载
结论: 获取带路径的文件名。
范例 3: 获取目录下所有文件路径
public class TestDemo4 {
public static void main(String[] args) {
File file = new File("D:");
lisrDir(file);
}
//使用递归遍历输出目录下所有文件路径
public static void lisrDir(File file){
if (file.isDirectory()){
File[] files = file.listFiles();
for (File f1 : files) {
lisrDir(f1);
}
}
System.out.println(file);
}
}
文件名修改
public class TestDemo5 {
public static void main(String[] args) throws IOException {
File oldFile = new File("d:"+File.separator+"old.txt");
oldFile.createNewFile();
File newFile = new File("d:"+File.separator+"new.txt");
if (oldFile.exists()){
oldFile.renameTo(newFile);
}
// newFile.delete();
}
}
批量修改字节文件名
package filenamecopy;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class renameuserfilename {
/****
* String类可能使用的方法
substring(int beginIndex)
截取从beginIndex到末尾的字符串并返回
substring(int beginIndex, int endIndex)
截取从beginIndex到endIndex的字符串并返回
concat(String str)
将指定字符串str连接到此字符串的结尾
indexOf(int ch)
返回指定字符在此字符串中第一次出现处的索引
indexOf(String str)
返回指定子字符串在此字符串中第一次出现处的索引
lastIndexOf(int ch)
返回指定字符在此字符串中最后一次出现处的索引
lastIndexOf(int ch, int fromIndex)
返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索
length() 返回此字符串的长度
replace(CharSequence target, CharSequence replacement)
使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串
replaceAll(String regex, String replacement)
使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 在目标文件夹下重命名
renamfile1("D:\\解密\\test\\10\\spark");
//拷贝别的目录下重命名
//reNameFile3("D:\\解密\\test\\10\\spark", "E:\\test\\10");
}
public static void reNameFile3(String oldfiles, String newfile)
throws IOException {
// File folder = new File("D:\\解密\\test\\10\\spark");
File folder = new File(oldfiles);
File newfiles = new File(newfile);
// 如果不存在,创建文件夹
if (!newfiles.exists()&&!newfiles.isDirectory()) {
/*
* 创建单级目录
* System.out.println("=====创建文件夹==========="+newfiles.mkdir());
* newfiles.mkdir();
*/
// 创建多级目录
newfiles.mkdirs();
System.out.println("=====创建文件夹===========" + newfiles.mkdirs());
}
// 获取该目录下所有文件的File数组
File[] fileArray = folder.listFiles();
int i = 1;
for (File f : fileArray) {
// System.out.println(f);
String name = f.getName();
int index = name.indexOf(":");
String newName = i + "." + name.substring(index + 1, name.length());
System.out.println(newName);
// File newFile = new File(folder,newName);
// f.renameTo(newFile);
i++;
// 封装数据源
/*
* //FileReader fr = new FileReader("c:\\a.txt"); FileReader fr =
* new FileReader(oldfiles+"\\"+name); // 封装目的地 //FileWriter fw =
* new FileWriter("d:\\b.txt"); FileWriter fw = new
* FileWriter(newfile+"\\"+newName); // 读写数据 // int ch = 0; int ch;
* while ((ch = fr.read()) != -1) { fw.write(ch); }
*
* //释放资源 fw.close(); fr.close();
*/
// 封装数据源
BufferedReader br = new BufferedReader(new FileReader(oldfiles
+ "\\" + name));
// 封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter(newfile
+ "\\" + newName));
// 读写数据
String line = null;
// 两种方式其中的一种一次读写一个字符数组
char[] chs = new char[1024];
int len = 0;
while ((len = br.read(chs)) != -1) {
bw.write(chs, 0, len);
bw.flush();
}
// 释放资源
bw.close();
br.close();
}
}
public static void reNamefile2(String oldfiles) {
// File folder = new File("D:\\解密\\test\\10\\spark");
File folder = new File(oldfiles);
// 获取该目录下所有文件的File数组
File[] fileArray = folder.listFiles();
if (!folder.exists()) {
return;// 重命名文件不存在
}
int i = 1;
for (File f : fileArray) {
// System.out.println(f);
String name = f.getName();
int index = name.indexOf(":");
String newName = i + "." + name.substring(index + 1, name.length());
System.out.println(newName);
File newFile = new File(folder, newName);
f.renameTo(newFile);
i++;
}
}
public static void renamfile1(String oldfiles) throws IOException {
File file = new File(oldfiles);
File[] list = file.listFiles();
// 如果目录下文件存在
if (file.exists() && file.isDirectory()) {
for (int i = 0; i < list.length; i++) {
// 取文件名子存入name中
String name = list[i].getName();
// 截取":"之前的字符串出来
int index = name.indexOf(":");
String name2 = name.substring(index + 1);
// 重命名并存入
int j = i + 1;
File dest = new File(oldfiles + "\\" + j + "." + name2);
list[i].renameTo(dest);
System.out.println(dest.getName());
/*
* if(newfile.exists())//若在该目录下已经有一个文件和新文件名相同,则不允许重命名
* System.out.println(newname+"已经存在!"); else{
* oldfile.renameTo(newfile); }
*/
}
}
}
public static void reNameFile0(String filespath){
File file = new File(filespath);
File[] list = file.listFiles();
// 如果目录下文件存在
if (file.exists() && file.isDirectory())
{
for (int i = 0; i < list.length; i++)
{
//取文件名子存入name中
String name = list[i].getName();
// 截取.之前的字符串出来
int index = name.indexOf(".");
// 截取后缀名字.qsv/.exe/.avi/.mp4出来
int index2 = name.lastIndexOf(".");
String name3 = name.substring(index2);
// 拼接字符串
String newName = "2019-4-18-" + (i + 1) + name3;
//重命名
File dest = new File(filespath + "\\" + newName);
list[i].renameTo(dest);
System.out.println(dest.getName());
}
}
}
}
处理前:
处理后:
字节流与字符流
输入流输出流
- 字节操作流:OutputStream(字节输出流)和InputStream(字节输入流)
- 字符操作流:Writer(字符输入流) 和 Reader(字符输出流)
不管使用哪一种操作流,
字节输出流OutputStream
是同一个操作输出流,实现了Closable 和 Flushable 接口,而Closeable 接口实现了AutoCloseable 接口
-
public abstract void write(int b) throws IOException
OutputStream 提供了三个输出方法
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
01 | public abstract void write(int b) throws IOException | method | 输出单个字节数据 |
02 | public void write(byte[] b) throws IOException | method | 输出全部字节数组数据 |
03 | public void write(byte[] b, int off, int len) throws IOException | method | 输出指定字节数组的数据 |
整个OutputStream 类中的write()方法都是针对字节数据进行处理的。
寻找FileOutputStream.
NO | 方法名称 | 类型 | 描述 |
---|---|---|---|
01 | public FileOutputStream(File file) throws FileNotFoundException | method | 设置文件输出流,每次都对原始数据进行覆盖 |
02 | public FileOutputStream(File file, boolean append) throws FileNotFoundException | method | 如果将append 的内容设置为true,对原始内容进行追加 |
范例:
public class Test1 {
public static void main(String[] args) throws FileNotFoundException, IOException {
//要进行磁盘输出的完整路径
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//append,值为true ,实现内容追加输出
OutputStream outputStream = new FileOutputStream(file,true);//获得输出流
//实现数据的输出需要将内容变为字节数组
outputStream.write("\r\n肚子饿了吗".getBytes());
outputStream.write("\r\n肚子饿了吗2".getBytes());
outputStream.write("\r\n肚子饿了吗3".getBytes());
//指定出数组第2个元素起输出5个元素。
outputStream.write("hello world!".getBytes(),2,5);
outputStream.close();//关闭输出流
}
}
字节输出流InputStream
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
01 | public FileInputStream(File file) throws FileNotFoundException | 构造 | |
02 | public abstract int read() throws IOException | 方法 | 读取单个字节数据,如果没有自己数据了,返回“-1" |
03 | public int read(byte[] b) throws IOException | 方法 | 将内容读取到字节数组之中,如果没有自己数据了,返回“-1" |
04 | public int read(byte[] b, int off, int len) throws IOException | 方法 | 将内容兑取到字节数组中,返回部分数据,如果没有数据返回‘-1’ |
可以使用FileInputStream子类对其进行实例化,以实现文件流的操作。
范例:
package com.zdy.stream;
import java.io.*;
/**
* Created by 逸足天涯
* on 3/21/2020.
*/
public class Test2{
public static void main(String[] args) throws FileNotFoundException, IOException {
//要进行磁盘输出的完整路径
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+File.separator+"info.txt");
if (file.exists()){
InputStream inputStream = new FileInputStream(file);//实例化输入流
byte data[] = new byte[1024];
inputStream.read(data); //将输入流中的内容读取到字节数组之中
System.out.println("{读取到的内容==\n=="+new String(data,0,data.length)+"}");//将读取到的字节数组内容转换为字符串在控制台输出
inputStream.close();
}
}
}
从JDK1.9 开始InputStream 追加了一个疯狂的方法getAllBytes(),这种方法的好处在于,开发者再考虑使用多大的书数组了,直接全部返回了,但是数据一多就会崩溃。
字符输出流Writer
在使用Writer 类 进行操作时,最大的数据特征是其可以进行字符串数据处理
* 输出方法 public void write(String str) throws IOException
* 后续版本才有了 CharSequence 接口的支持,就可以实现String,Stringbuffer,StringBuilder的实例
范例:使用FileWaiter进行输出;
public class Test3 {
public static void main(String[] args) throws FileNotFoundException, IOException {
//要进行磁盘输出的完整路径
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info2.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Writer out = new FileWriter(file);//实例化Writer类对象
out.write("www.baidu.com");
out.append("hello append");
out.close();
}
}
使用Writer 可以实现 与OutputStream 类似的功能,其最大的优势在于可以直接实现对字符的操作。
字符输入流(Reader)
范例
public class test4 {
public static void main(String[] args) throws FileNotFoundException, IOException {
//要进行磁盘输出的完整路径
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info2.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Reader in = new FileReader(file);//实例化Writer类对象
char[] data = new char[1024];
int len = in.read(data);
System.out.println(new String(data,0,len));
in.close();
}
}
使用try(){} 实现字节流的自动关闭。同理以上3个实例也可以实现自动关闭,因为他们都实现了InterfacAutoCloseable接口。
public class test4 {
public static void main(String[] args) {
//要进行磁盘输出的完整路径
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info2.txt");
if(file.exists()){
try( Reader in = new FileReader(file)) {
char[] data = new char[1024];//新建一个字符数,
int len = in.read(data);//把文件内容存入数组
System.out.println(new String(data,0,len));//控制台输出
}catch (Exception e){
System.err.println(e);
}
}
}
}
字节流和字符流的区别
要想明白字节流和字符流的区别,首先明白
字节和字符的区别:
-
byte 是字节数据类型 ,是有符号型的,占1 个字节;大小范围为-128—127 。
-
char 是字符数据类型 ,是无符号型的,占2字节(Unicode码 );大小范围 是0—65535 ;char是一个16位二进制的Unicode字符,JAVA用char来表示一个字符 。
下面用实例来比较一下二者的区别:
- Char是无符号型的,可以表示一个整数,不能表示负数;而byte是有符号型的,可以表示-128—127 的数;如:
char c = (char) -3; // char不能识别负数,必须强制转换否则报错,即使强制转换之后,也无法识别
System.out.println(c);
byte d1 = 1;
byte d2 = -1;
byte d3 = 127; // 如果是byte d3 = 128;会报错
byte d4 = -128; // 如果是byte d4 = -129;会报错
System.out.println(d1);
System.out.println(d2);
System.out.println(d3);
System.out.println(d4);
结果为:
?
1
-1
127
-128
- char可以表中文字符,byte不可以,如:
char e1 = '中', e2 = '国';
byte f= (byte) '中'; //必须强制转换否则报错
System.out.println(e1);
System.out.println(e2);
System.out.println(f);
结果为:
中
国
45
- char、byte、int对于英文字符,可以相互转化,如:
byte g = 'b'; //b对应ASCII是98
char h = (char) g;
char i = 85; //U对应ASCII是85
int j = 'h'; //h对应ASCII是104
System.out.println(g);
System.out.println(h);
System.out.println(i);
System.out.println(j);
结果:
98
b
U
104
已经接触了两种数据流操作,
字节操作,属于基础的二进制流操作。在网络、文件等操作。
字节数据不方便对于中文的处理,所以中文处理应该使用字符流。
在进行网络传输或者磁盘数据存储的时候,所有存放内容都属于字节数据。
范例: 体验字符流在转换过程中有缓冲区。
将test1 代码去掉 outputStream.close();//关闭输出流。执行程序,发现目标文件写入代码。
将test3 代码去掉 out.close(); //关闭输出流,执行程序,查看目标文件,内容未写入。
原因: 字符流具有缓冲区,数据流关闭后,数据写入目标文件,未关闭时,数据在缓冲区内,
可以添加 out.flush(); 方法清空缓冲区。再次执行程序。发现即使没有关闭输出流,数据依然写入文件。
转换流
为了方便的实现字节流和字符流的转换处理,提供了2个类OutputStreamWriter 和InputStreamReader
通过观察源码发现OutputStreamWriter 继承Writer类,构造方法里是一个OuputStream 实例。
InputStreamReader类继承Reader类,同时构造方法里是一个InputStream实例。
范例: 观察数据流的转化
package com.zdy.stream;
import java.io.*;
/**
* Created by 逸足天涯
* on 3/21/2020.
*/
public class Test5 {
public static void main(String[] args) throws FileNotFoundException, IOException {
//要进行磁盘输出的完整路径
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info3.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//append,值为true ,实现内容追加输出
OutputStream outputStream = new FileOutputStream(file);//获得输出流
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);//字节流转字符流
outputStreamWriter.write("www.baidu.com");//直接输出字符串
outputStreamWriter.write("\r\n你好世界");//直接输出字符串
outputStreamWriter.append("\r\nnhello world");
outputStreamWriter.close();//关闭输出流
}
}
文件Copy
要复制的文件可能是文本文件也可能是二进制文件,所有考虑通用性,使用字节流
由于要因该cpoy 的文件很大,因该采用边读边写的模式。
范例:
class CopyUtil{
private File srcFile;
private File desFile;
public CopyUtil(File srcFile,File desFile) {
//如果没错,获取源文件和目标文件路径
this.srcFile = srcFile;
this.desFile = desFile;
}
/*
* 实现复制的操作处理
* @return 返回本次花费的时间
* */
public int copy() throws IOException {
long start = System.currentTimeMillis();
if(!this.srcFile.exists()){
throw new FileNotFoundException("源文件不存在");
}
if(!this.desFile.getParentFile().exists()){
this.desFile.getParentFile().mkdirs();//创建目标父目录
}
InputStream input = null;
OutputStream output = null;
try{
input = new FileInputStream(this.srcFile);
output = new FileOutputStream(this.desFile);
} catch (IOException e) {
throw e;
} finally {
if (input!=null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (output!=null){
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
return (int) (end-start);
}
}
public class CopyDemo {
public static void main(String[] args) throws IOException {
File oldfile = new File("d:" + File.separator + "社会工程3本.pdf");
File newfile = new File("d:" + File.separator + "images" + File.separator + "新社会工程3本.pdf");
CopyUtil copyUtil = new CopyUtil(oldfile,newfile);
int time = copyUtil.copy();
System.out.println("复制文件花费的时间:" + time);
}
}
但是JDK 1.9 开始,在InputStream中出现了一个新方法。
public long transferTo(OutputStream out) throws IOException
直接把输入流转成输出流。实现文件复制。
上面代码可以写成
class CopyUtil{
private File srcFile;
private File desFile;
public CopyUtil(File srcFile,File desFile) {
//如果没错,获取源文件和目标文件路径
this.srcFile = srcFile;
this.desFile = desFile;
}
/*
* 实现复制的操作处理
* @return 返回本次花费的时间
* */
public int copy() throws IOException {
long start = System.currentTimeMillis();
if(!this.srcFile.exists()){
throw new FileNotFoundException("源文件不存在");
}
if(!this.desFile.getParentFile().exists()){
this.desFile.getParentFile().mkdirs();//创建目标父目录
}
InputStream input = null;
OutputStream output = null;
try{
input = new FileInputStream(this.srcFile);
output = new FileOutputStream(this.desFile);
input.transferTo(output);
} catch (IOException e) {
throw e;
} finally {
if (input!=null){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (output!=null){
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
long end = System.currentTimeMillis();
return (int) (end-start);
}
}
public class CopyDemo {
public static void main(String[] args) throws IOException {
File oldfile = new File("d:" + File.separator + "社会工程3本.pdf");
File newfile = new File("d:" + File.separator + "images" + File.separator + "新社会工程3本.pdf");
CopyUtil copyUtil = new CopyUtil(oldfile,newfile);
int time = copyUtil.copy();
System.out.println("复制文件花费的时间:" + time);
}
}
字符编码
- GBK/GB2312:BGK 包含简体中文和繁体中文,BG2312只包含简体中文。
- ISO8859-1: 是一个国际编码,可以描述任何文字,单对于图形文字则需要转码。
- UNiCODE : 是一个不错的编码,使用16 进制,可世界上任何编码。占用空间大
- UTF编码: 由ISO8859-1和UNICODE,在需要使用图形化文字的时候使用16 进制,在UTF-8使用1~4字节为每个字符编码:该编码主要由UTF-8 和UTF-16.
范例:获取当前系统的一些环境属性。
内存流
内存流实现临时文件的处理
//内存流操作
public class TestDemo {
public static void main(String[] args) throws IOException {
InputStream input = new ByteArrayInputStream("www.baidu.com".getBytes());
OutputStream output = new ByteArrayOutputStream();
int data=0;
//input.read() 从输入流中读取下一个字节的数据。值字节是
//
//*以<code>0</code>到范围内的<code>int</code>返回
while((data=input.read()) !=-1){
//将数据一个一个写入输出流
output.write(Character.toUpperCase(data));
}
System.out.println(((ByteArrayOutputStream) output).toString());
output.close();
input.close();
}
}
ByteArrayOutputStream一个特别重要的方法 public byte[] toByteArray()
public class TestDemo2 {
public static void main(String[] args) throws IOException {
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info4.txt");
InputStream input = new FileInputStream(file);
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte data[] = new byte[1024];
int len = 0;
while((len=input.read(data))!=-1){
output.write(data,0,len);
}
System.out.println(new String(output.toByteArray()));
output.close();
input.close();
}
}
JDK 1.9 后使用 public byte[] readAllBytes() throws IOException 替代上面的代码
public class TestDemo3 {
public static void main(String[] args) throws Exception {
File file = new File("d:" + File.separator+"mldn"+File.separator+"message"+ File.separator+"info4.txt");
if(file.exists()){
InputStream inputStream = new FileInputStream(file);
byte bytes[] = inputStream.readAllBytes();
System.out.println(new String(bytes));
inputStream.close();
}
}
}
管道流
管道和线程有关,但是,实话讲,这样的设计有些啰嗦,多个线程可以实现一个进程的数据共享,但是多个进程的数据无法共享。因为cpu 的资源无法无法共享。
实现两个进程之间的通信,称作管道。
Java 提供2个线程之间的通信,叫做管道。
在Java 中实现线程之间的通信,提供了2个类。PipeOutputStream 和PipeInputStream两个类。
范例:
package com.zdy.管道;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* Created by 逸足天涯
* on 3/21/2020.
*/
class SendThread implements Runnable{
private PipedOutputStream pipedOutputStream = new PipedOutputStream();
public void setPipedOutputStream(PipedOutputStream pipedOutputStream) {
this.pipedOutputStream = pipedOutputStream;
}
public PipedOutputStream getPipedOutputStream() {
return pipedOutputStream;
}
@Override
public void run() {
try {
this.pipedOutputStream.write("晚上不考试了,直接下课".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ReceiveThread implements Runnable{
private PipedInputStream pipedInputStream = new PipedInputStream();
@Override
public void run() {
byte data [] = new byte[1024];
try {
int len = this.pipedInputStream.read(data);
System.out.println("接收数据"+ new String(data,0,len));
} catch (IOException e) {
e.printStackTrace();
}
}
public PipedInputStream getPipedInputStream() {
return pipedInputStream;
}
public void setPipedInputStream(PipedInputStream pipedInputStream) {
this.pipedInputStream = pipedInputStream;
}
}
public class TestDemo {
public static void main(String[] args) throws IOException {
SendThread sendThread = new SendThread();
ReceiveThread receiveThread = new ReceiveThread();
sendThread.getPipedOutputStream().connect(receiveThread.getPipedInputStream());//管道对接
new Thread(sendThread).start();
new Thread(receiveThread).start();
}
}
RandomAccessFile
RandomAccessFile 访问文件内的信息读取需要的数据。不需要的不读取。
但是,所读取数据的长度必须统一。
RandomAcessFile 支持内容的输出与输入
范例
//写入数据
public class TestDemo {
public static void main(String[] args) throws IOException {
File file = new File("d:"+File.separator+"member.text");
String name[] = new String[]{"张三","lisi","王五"};
int ages [] = new int[]{17,18,19};
RandomAccessFile randomAccessFile = new RandomAccessFile(file,"rw");//读写模式
for (int x = 0;x< name.length;x++){
randomAccessFile.write(name[x].getBytes()); //写入字符串
randomAccessFile.writeInt(ages[x]);//写入数字
}
randomAccessFile.close();
}
}
此时输出到文件的数据都属于二进制的数据内容,那么对于此时的内容只能够利用RandomAccessFile 读取
-
public int skipBytes(int n) throws IOException// 向下跳
-
public void seek(long pos) throws IOException//向回跳
读取数据
//读取数据
public class TestDemo1 {
public static void main(String[] args) throws IOException {
File file = new File("d:"+File.separator+"member.txt");
RandomAccessFile randomAccessFile = new RandomAccessFile(file,"r");//只读
{
randomAccessFile.skipBytes(12);
byte data[] = new byte[8];
randomAccessFile.read(data);
System.out.println(String.format("姓名: %s、年龄%s",new String(data),randomAccessFile.readInt()));
//读取zhangsan 的数据
randomAccessFile.seek(0);
randomAccessFile.read(data);
System.out.println(String.format("姓名: %s、年龄%s",new String(data),randomAccessFile.readInt()));
//读取王五
randomAccessFile.skipBytes(12);
randomAccessFile.read(data);
System.out.println(String.format("姓名: %s、年龄%s",new String(data),randomAccessFile.readInt()));
}
randomAccessFile.close();
}
}
打印流
PrintWriter
设计一个类,实现个中数据类型的输出
范例: 最初的设计方案
package com.zdy.打印流;
import java.io.*;
/**
* Created by 逸足天涯
* on 3/22/2020.
*/
class PrintUtil implements Closeable{//设计一个打印流的功能类,支持各种数据类型流输出
private OutputStream outputStream;
public PrintUtil(OutputStream outputStream){//设置输出位置
this.outputStream = outputStream;
}
public void print(String str){
try {
this.outputStream.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public void print(int num){
this.print(String.valueOf(num));
}
public void println(String str){
this.print(str+"\r\n");
}
public void println(int num){
this.println(String.valueOf(num));
}
@Override
public void close() throws IOException {
this.outputStream.close();
}
}
//功能数据直接输出到文件内
public class TestDemo {
public static void main(String[] args) throws IOException {
PrintUtil pu = new PrintUtil(new FileOutputStream(new File("d:"+File.separator+"info.txt")));
pu.print("姓名:dog");
pu.println("、年龄");
pu.println(64);
System.out.println("内容已经添加到"+ " d:\\info.txt");
pu.close();
}
}
为了解决上述问题,JDK 提供了2个类 PrintStream 和 PrintWriter 两个类。
使用打印流输出 实现上述内容同样功能
//功能数据直接输出到文件内
public class TestDemo1 {
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileOutputStream(new File("d:"+File.separator+"info.txt")));
pw.print("姓名:dog");
pw.println("、年龄");
pw.println(64);
System.out.println("内容已经添加到"+ " d:\\info.txt");
pw.close();
}
}
public PrintWriter printf(String format, Object... args)
实现格式化输出。
//功能数据直接输出到文件内
public class TestDemo1 {
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileOutputStream(new File("d:"+File.separator+"info.txt")));
String name= "god";
int age = 10000000;
double sorce = 100.12423432;
pw.printf("姓名:%s、年龄:%d、成绩:%5.2f",name,age,sorce);
System.out.println("内容已经添加到"+ " d:\\info.txt");
pw.close();
}
}
结论: 对于明文可以使用PrintWriter .对于二进制文件的优先建议使用PrintStream.尤其是中文。
打印流使用装饰设计模式
对象流的使用
使用对象流实现对对象的序列化和反序列化
要想使对象序列化,必须实现 Serializable 接口。
package com.zdy;
import java.io.Serializable;
/**
* Created by 逸足天涯
* on 3/22/2020.
*/
//实现 Serializable 表示此对象可以序列化
public class Person implements Serializable {
private static final long serialVersionUID = 7592930394427200495L;
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "姓名:"+name+"\n年龄:"+age;
}
}
序列化
package com.zdy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
/**
* Created by 逸足天涯
* on 3/22/2020.
*/
public class SerObject {
public static void main(String[] args) throws IOException {
//实例化一个需要序列化的Person对象
Person jack = new Person("jack", 12);
//生成一个文件对象,文件不存在将自动创建文件
File f = new File( new File("").getAbsolutePath()+ File.separator + "serTest.txt");
//构造一个对象输出流oos
ObjectOutputStream oos = null;
//构造一个文件输出流
FileOutputStream fileOutputStream = new FileOutputStream(f);
//构造对象输出流
oos = new ObjectOutputStream(fileOutputStream);
//序列化一个对象到文件变成二进制内容
oos.writeObject(jack);
oos.close();
}
}
反序列化
package com.zdy;
import java.io.*;
/**
* Created by 逸足天涯
* on 3/22/2020.
*/
public class ReSerObject {
public static void main(String[] args) throws Exception {
//生成一个文件对象,文件不存在将自动创建文件
File f = new File( new File("").getAbsolutePath()+ File.separator + "serTest.txt");
//新建一个文件输入流
FileInputStream fileInputStream = new FileInputStream(f);
//新建一个对象输入流
ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
//读取输入流中对象
Person o = (Person)objectInputStream.readObject();
//输出对象
System.out.println(o.toString());
}
}