第十一章 Java IO编程
11.1 文件操作类:File
java.io包中,如果要进行文件自身操作(创建,删除),只能依靠java.io.File类完成。
NO. | 方法 | 类型 | 描述 |
---|---|---|---|
1 | public File(String pathname) | 构造 | 传递完整文件操作路径 |
2 | public File(File parent,String child) | 构造 | 设置父路径与子文件路径 |
3 | public boolean createNewFile() thorws IOException | 普通 | 创建新文件 |
4 | public boolean exists() | 普通 | 判断给定路径是否存在 |
5 | public boolean delete() | 普通 | 删除指定路径的文件 |
6 | public File getParentFile() | 普通 | 取得当前路径的父路径 |
7 | public boolean mkdirs() | 普通 | 创建多级目录 |
8 | public long length() | 普通 | 取得文件大小,以字节为单位返回 |
9 | public boolean isFile() | 普通 | 判断给定路径是否是文件 |
10 | public boolean isDirectory() | 普通 | 判断给定路径是否是目录 |
11 | public long lastModified() | 普通 | 取得文件的最后一次修改日期时间 |
12 | public String[] list() | 普通 | 列出指定目录中的全部内容 |
13 | public File[] listFiles() | 普通 | 列出所有的路径以File类对象包装 |
文件基本操作
public class TestDemo {
public static void main(String[] args) throws Exception {
File file=new File("d:\\test.txt");
if (file.exists()){
file.delete();
}else {
System.out.println(file.createNewFile());
}
}
}
在Windows系统下,使用\\做分隔符,如果程序运行在Linux系统中,则路径的分隔符为/。
为此java中提供了一个路径分隔符常量:public static final String separator
File file=new File(“d:+File.separator+test.txt”);
创建带路径的文件
public class TestDemo {
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator+"demo"+File.separator+"test.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
System.out.println(file.createNewFile());
}
}
取得文件或目录的信息
package com.company;
import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class TestDemo {
public static void main(String[] args) throws Exception {
File file=new File("d:"+File.separator+"DG5421239_x86.zip");
if (file.exists()){
System.out.println("是否是文件:"+(file.isFile()));
System.out.println("是否是目录:"+(file.isDirectory()));
//文件大小是按照字节单位返回的数字,所以需要字节单元转换为兆的单元
System.out.println("文件大小:"+(new BigDecimal
((double)file.length()/1024/1024).
divide(new BigDecimal(1),2,BigDecimal.ROUND_CEILING))+"M");
//返回的日期是以long的形式返回,可以利用SimpleDateFoemat进行格式化操作
System.out.println("上次修改时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(file.lastModified())));
}
}
}
列出目录信息
public class TestDemo {
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator);
if (file.isDirectory()) {
File result[]=file.listFiles();
for (int x = 0; x <result.length;x++){
System.out.println(result[x]);
}
}
}
}
列出指定目录下的所有文件以及子目录信息
public class TestDemo {
public static void main(String[] args) throws Exception {
File file =new File("d:"+File.separator);
print(file);
}
public static void print(File file){
if (file.isDirectory()) {
File result[]=file.listFiles();
if (result!=null) {
for (int x = 0; x < result.length; x++) {
print(result[x]);
}
}
}
System.out.println(file);
}
}
11.2 字节流与字符流
输入与输出两种方式:
- 字节流:InputStream(输入字节流)、OutputStream(输出字节流)
- 字符流:Reader(输入字符流)、Writer(输出字符流)
基本操作形式:
- 第一步:通过File类定义一个要操作文件的路径;
- 第二步:通过字节流或字符流的子类对象为父类对象实例化;
- 第三步:进行数据的读,写操作;
- 第四步:数据流属于资源操作,资源操作必须关闭。
对于四个操作类都属于抽象类。
11.2.1 字节输出流:OutputStream
常用方法
public void close() thorws IOException:关闭字节输出流
public void flush() throws IOException:强制刷新
public abstract void write(int b) throws IOException:输出单个字节
public void write(byte[] b)throws IOException:输出全部字节数组数据
public void write(byte[] b,int off,int len)throws IOException:输出部分字节数组数据
文件内容的输出
public class TestDemo {
public static void main(String[] args) throws Exception {
//1.定义要输出文件的路径
File file=new File("d:"+File.separator+"demo"+File.separator+"mldn.txt");
//此时由于目录不存在,所以文件不能输出,应该首先创建目录
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
//2.应该使用OutputStream和其子类进行对象的实例化,此时目录存在,文件还不存在。
OutputStream output=new FileOutputStream(file);
//字节输出流需要使用byte类型,需要将String类对象变为字节数组
String str="更多课程资源请访问:www.baidu.com";
byte data[]=str.getBytes();
//进行写操作
output.write(data);
//进行清除操作
output.close();
}
}
输出部分数组内容
output.write(data,6,6);
对于已有文件进行追加操作
OutputStream output=new FileOutputStream(file,true);
11.2 字节输入流:InputStream
常用方法
- public void close() throws IOException:关闭字节输入流
- public abstract int read() throws IOException:读取单个字节
- public int read(byte[] b)throws IOException :将数据读取到字节数组中,同时返回读取长度。
- public int read(byte[] b,int off,int len)throws IOException :将数据读取到部分字节数组中,同时返回读取的数据长度。
关于InputStream类中最为重要的3个read()方法
- 读取单个字节:public abstract int read() throws IOException(返回读取的字节内容,如果已经没有内容,则读取后返回“-1”)
- 将读取的数据保存在字节数组里(一次性读取多个数据):public int read(byte[] b)throws IOException (返回读取的数据长度,如果已经读取到结尾,则返回-1)
- 将读取的数据保存在部分字节数组里:public int read(byte[] b,int off,int len) throws IOException(读书数据部分长度)
FilelnputStream类的构造方法
public FileIputStream(File file)throws FileNotFoundException:设置要读取的文件数据路径
数据读取操作
public class TestDemo {
public static void main(String[] args) throws Exception {
//1.定义要输出文件的路径
File file=new File("d:"+File.separator+"demo"+File.separator+"mldn.txt");
if (file.exists()){
//2.使用InputStream进行读取
InputStream input=new FileInputStream(file);
byte data[]=new byte[1024];
int foot=0;
int temp=0;
while( (temp=input.read())!=-1){
data[foot++]=(byte) temp;
}
input.close();
System.out.println("["+new String(data,0,foot)+"]");
}
}
}
11.2.3 字符输出流 Writer
Writer类的常用操作方法
- public void close() throws IOException:关闭字节输出流
- public void flush() throws IOException:强制刷新
- public Writer append(CharSequence csq)throws IOException:追加数据
- public void writer(String str ) throws IOException:输出字符串数据
- public void write(char[] cbuf)throws IOException:输出字符数组数据
FileWriter类的常用方法
- public FileWriter(File file )throws IOException :设置输出文件
- public FileWriter(File file ,boolean append)throws IOException:设置输出文件以及是否进行数据追加。
public class TestDemo {
public static void main(String[] args) throws Exception {
//1.定义要输出文件的路径
File file=new File("d:"+File.separator+"demo"+File.separator+"mldn.txt");
if (!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
Writer out=new FileWriter(file);
String str="更多课程访问:www.baidu.com";
out.write(str);
out.close();
}
}
11.2.4 字符输入流:Reader
Reader类的常用方法
- public void close() throws IOException:关闭字节输入流
- public int read() throws IOException :读取单个数据
- public int read() throws IOException:读取单个字符
- public int read(char[] cbuf)throws IOException:读取数据到字符串组中,返回读取长度
- public long skip(long n )throws IOException:跳过字节长度
使用Reader读取数据
public class TestDemo {
public static void main(String[] args) throws Exception {
//1.定义要输出文件的路径
File file=new File("d:"+File.separator+"demo"+File.separator+"mldn.txt");
if (file.exists()){
Reader in=new FileReader(file);
char data[]=new char[1024];
int len=in.read(data);
in.close();
System.out.println(new String(data,0,len));
}
}
}
11.2.5 字节流和字符流的区别
字节流直接与终端文件进行数据交互,字符流需要将数据经过缓冲区处理才与终端文件数据交互。
如果有特殊情况不能关闭字符输出流,可以使用flush()方法强制清空缓冲区。
11.3 转换流
字节流通过向上转型可以转换为字符流
实现输出流转换
public class TestDemo {
public static void main(String[] args) throws Exception {
//1.定义要输出文件的路径
File file=new File("d:"+File.separator+"demo"+File.separator+"mldn.txt");
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
OutputStream output=new FileOutputStream(file);
Writer out=new OutputStreamWriter(output);
out.write("更多课程请访问:www.baidu.com");
out.flush();
out.close();
}
}
11.4 案例:文件复制
两种方法
- 法一:将所有的文件内容先一次性读取到程序中,再一次性输出。缺点:如果要读取的文件量过大,就会造成程序的崩溃。
- 法二:采用边读边输出的操作方式,每次从源文件输入流中读取数据,而后将这部分数据交给输出流输出,这样的做法不会占用较大的内存空间,但是会适当损耗一些时间。
使用的类与方法
-
InputStream类:public int read(byte[] b)throws IOException;(将内容读取到字节数组中,如果没有数据则返回-1,否则读取长度)
-
OutputStream类:public void write(byte[] b)throws IOException. (要设置的字节数组实际上就是在read()方法里面使用的数组;数据输出一定是从字节数组的第0个元素开始,输出读取的数据长度。)
实现文件复制操作
public class TestDemo { public static void main(String[] args) throws Exception { //取得复制开始的时间 long start=System.currentTimeMillis(); if (args.length!=2){ System.out.println("命令执行错误!"); System.exit(1); } //如果输入参数正确,应该进行源文件有效性的验证 File inFile=new File(args[0]); if (!inFile.exists()){ System.out.println("源文件不存在,请输入有效入径。"); System.exit(1); } //如果此时源文件正确,就需要定义输出文件,同时要考虑到输出文件有目录 File outFile=new File(args[1]); if (!outFile.getParentFile().exists()){ outFile.getParentFile().mkdirs(); //创建目录 } //实现文件内容的复制,分别定义输出流和输入流对象 InputStream intput=new FileInputStream(inFile); OutputStream output=new FileOutputStream(outFile); int temp=0; byte data[]=new byte[1024]; //将每次读取进来的数据保存在字节数组里面,并且返回读取的个数 while ((temp=intput.read(data))!=-1){ output.write(data,0,temp); } intput.close(); output.close(); long end=System.currentTimeMillis(); System.out.println("复制所花费的时间:"+(end-start)); } }
11.5 字符编码
GBK、GB2312:中文的国际编码,其中GBK包含简体中文与繁体中文两种,而GB2312只包含简体中文;
ISO8859-1:是国际编码,可以描述任何文字信息;
UNICODE:是十六进制编制,但是在传递字符信息时会造成传输的数据较大。
UTF编码:是一种UNICODE的可变长度编码,常见的编码为UTF-8编码。
public class TestDemo {
public static void main(String[] args) throws Exception {
File file=new File("d:"+File.separator+"demo"+File.separator+"mldn.txt");
OutputStream output=new FileOutputStream(file);
//强制改变文件的编码,此操作可以通过String类的getBytes()方法实现
output.write("更多课程访问:www.baidu.com".getBytes("GBK"));
output.close();
}
}
11.6 内存流
内存流的两种方式
- 字节内存流:ByteArrayInputStream(内存字节输入流)、ByteArrayOutputStream(内存字节输出流)
- 字符内存流:CharArrayReader(内存字符输入流)、CharArrayWriter(内存字符输出流)
字母转大小写
- 转小写字母:public static char toLowerCase(char ch);
- 转小写字母(利用字母编码转换):public static int toLowerCase(int codePoint);
- 转大写字母:public static char toUpperCase(char ch)
- 转大写字母(利用字母编码转换):public static int toUpperCase(int codePoint)
实现文件的合并读取
public class TestDemo {
public static void main(String[] args) throws Exception {
File fileA=new File("d:"+File.separator+"into.txt");
File fileB=new File("d:"+File.separator+"outto.txt");
InputStream inputA=new FileInputStream(fileA);
InputStream inputB=new FileInputStream(fileB);
ByteArrayOutputStream output=new ByteArrayOutputStream();
int temp=0;
while ((temp=inputA.read())!=-1){
output.write(temp);
}
while ((temp=inputB.read())!=-1){
output.write(temp);
}
//现在所有的内容都保存在了内存输出流里面,所有的内容为字节数组取出
byte data[]=output.toByteArray();
output.close();
inputA.close();
inputB.close();
System.out.println(new String(data));
}
}
11.7 打印流
在java中主要利用OutputStream类主要是进行数据输出。
定义打印流工具类
package com.company;
import java.io.IOException;
import java.io.OutputStream;
public class PrintUtil {
private OutputStream output;
public PrintUtil(OutputStream output){
this.output=output;
}
public void print(int x){
this.print(String.valueOf(x));
}
public void print(String x){
try{
this.output.write(x.getBytes());
}catch (IOException e){
e.printStackTrace();
}
}
public void print(double x){
this.print(String.valueOf(x));
}
public void println(int x){
this.print(String.valueOf(x));
}
public void println(String x){
this.print(x.concat("\n"));
}
public void println(double x){
this.println(String.valueOf(x));
}
public void close(){
try{
this.output.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
public class TestDemo {
public static void main(String[] args) throws Exception {
PrintUtil pu=new PrintUtil(new FileOutputStream(new File("d:"+File.separator+"yootk.txt")));
pu.print("优秀教育:");
pu.println("www.dadaf");
pu.println(1+1);
pu.println(1.1+1.1);
pu.close();
}
}
PrintStream类的常用操作方法
public PrintStream(OutputStream out):通过已有OutputStream out确定输出目标
public void print(数据类型 参数名称):输出各种常见数据类型
public void println(数据类型 参数名称):输出各种常见数据类型,并追加一个换行
格式化输出
public class TestDemo {
public static void main(String[] args) throws Exception {
String name="朱小东";
int age=19;
double score=59.24452;
PrintStream pu=new PrintStream(new FileOutputStream(new File("d:"+File.separator+"yootk.txt")));
pu.printf("姓名:%s,年龄:%d,成绩:%5.2f",name,age,score);
pu.close();
}
}
11.8 System类的IO的支持
System.err:显示器上错误输出
System.out:显示器上信息输出
System.in:键盘数据输入
错误输出
public class TestDemo {
public static void main(String[] args) throws Exception {
try{
Integer.parseInt("abc");
}catch (Exception e){
System.err.println(e);
}
}
}
System.err是输出不希望用户看见的异常、System.out是输出希望用户看到的信息。
利用OutputStream实现屏幕输出
public class TestDemo {
public static void main(String[] args) throws Exception {
OutputStream out=System.out;
out.write("www.baidu.com".getBytes());
}
}
系统输入:System.in
public class TestDemo {
public static void main(String[] args) throws Exception {
InputStream input=System.in;
StringBuffer buf=new StringBuffer();
System.out.print("请输入数据:");
int temp=0;
while ((temp=input.read())!=-1){
if (temp=='\n'){
break;
}
buf.append((char) temp);
}
System.out.println("输出数据为:"+buf);
}
}
11.9 字符缓冲流:BufferedReader
为了可以进行完整数据的输入操作,最好的做法是采用缓冲区的方式对输入的数据进行暂存,而后程序可以利用输入流一次性读取内容。
- 字符缓冲区流:BufferedReader、BufferedWriter;
- 字节缓冲区流:BufferedInputStream、BufferedOutputStream。
public BufferedReader(Reader in):设置字符输入流
public String readLine() throws IOException:读取一行数据,默认以“\n"为分隔符。
判断输入内容
public class TestDemo {
public static void main(String[] args) throws Exception {
BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
boolean flag=true;
while (flag){
System.out.print("请输入年龄:");
String str=buf.readLine();
if (str.matches("\\d{1,3}")){
System.out.println("年龄是:"+Integer.parseInt(str));
flag=false;
}else {
System.out.println("年龄输入错误,应该由数字所组成。");
//该程序利用正则去判断
}
}
}
}
读取文件
public class TestDemo {
public static void main(String[] args) throws Exception {
File file=new File("D:"+File.separator+"yootk.txt");
//使用文件输入流实例化BufferedReader类对象
BufferedReader buf=new BufferedReader(new FileReader(file));
String str=null;
while ((str=buf.readLine())!=null){
System.out.println(str);
}
buf.close();
}
}
11.10 扫描流:Scanner
- public Scanner(InputStream source):接收InputStream输入流对象,此为输入源
- public boolean hasNext():判断是否有数据输入
- public String next():取出输入数据,以String形式返回
- public boolean hasNextXxx():判断是否有指定类型数据存在
- public 数据类型 nextXxx():取出指定数据类型的数据
- public Scanner useDelimiter(String pattern):设置读取的分隔符
利用Sanner实现键盘数据输入
public class TestDemo {
public static void main(String[] args) throws Exception {
Scanner scan=new Scanner(System.in);
System.out.println("请输入内容:");
if (scan.hasNext()){
System.out.println("输出内容:"+scan.next());
}
scan.close();
}
}
输入一个数字–double
public class TestDemo {
public static void main(String[] args) throws Exception {
Scanner scan=new Scanner(System.in);
System.out.println("请输入成绩:");
if (scan.hasNextDouble()){
double score=scan.nextDouble();
System.out.println("输出内容:"+score);
}else {
System.out.println("输入的不是数字,错误!");
}
scan.close();
}
}
正则验证
public class TestDemo {
public static void main(String[] args) throws Exception {
Scanner scan=new Scanner(System.in);
System.out.println("请输入生日:");
if (scan.hasNext("\\d{4}-\\d{2}-\\d{2}")){
String bir=scan.next("\\d{4}-\\d{2}-\\d{2}");
System.out.println("输出内容:"+bir);
}else {
System.out.println("输入生日格式错误!");
}
scan.close();
}
}
读取文件
public class TestDemo {
public static void main(String[] args) throws Exception {
Scanner scan = new Scanner(new FileInputStream("d:" + File.separator + "demo" + File.separator + "mldn.txt"));
scan.useDelimiter("\n");
while (scan.hasNext()) {
System.out.println(scan.next());
//中文读取不出来,会乱码。
}
scan.close();
}
}
11.11 对象序列化
但是在很多时候可能需要在JVM进程结束后对象依然可以被保存下来,或者在不同的JVM进程中要进行对象传输,这个时候就要采用对象序列化的方式进行处理。
序列化:将对象序列化为格式指定的二进制数据
反序列化:将系列化的二进制对象信息转换回对象内容。
- public ObjectOutStream(OutputStream out)throws IOException:指定对象序列化的输出流
- public final void writeObject(Object obj)throws IOException:序列化对象
- public ObjectInputStream(InputStream in)throws IOException:指定对象反序列化的输入流
- public final Object readObject()throws IOException,ClassNotFoundException:从输入流中读取对象
定义一个可以被序列化对象的类
import java.io.Serializable;
@SuppressWarnings("serial")
public class Book implements Serializable {
private String title;
private double price;
public Book(String title,double price){
this.title=title;
this.price=price;
}
@Override
public String toString(){
return "书名:"+this.title+"价格:"+this.price;
}
}
实现序列化对象操作
public class TestDemo {
public static void main(String[] args) throws Exception {
ser();
}
public static void ser()throws Exception{
ObjectOutputStream oos=new ObjectOutputStream(new ObjectOutputStream
(new FileOutputStream(new File("d:"+File.separator+"demo"+File.separator+"mldn.txt"))));
oos.writeObject(new Book("java开发",19.2));
oos.close();
}
}
反序列化操作
public class TestDemo {
public static void main(String[] args) throws Exception {
ser();
}
public static void ser()throws Exception{
ObjectInputStream oos=new ObjectInputStream(new FileInputStream(new File("d:"+File.separator+"demo"+File.separator+"mldn.txt")));
Object obj=oos.readObject();
Book book=(Book) obj;
System.out.println(book);
oos.close();
}
}
transient关键字用此关键字定义的属性无法被序列化。