IO流
在java.io包下主要包括输入、输出两种IO流,每种输入、输出流又分为字节流和字符流两大类
字节流以字节为单位来处理输入、输出操作
字符流以字符为单位来处理输入、输出操作
File类
File类用来将文件或者文件夹封装成对象,方便对文件或文件夹的属性信息进行操作,创建、删除、重命名等操作
File不能访问文件内容本身,需要使用输入、输出流
File类可以使用文件路径字符串来创建File实例,可以是绝对或相对路径
Field:
static String separator //表示系统相关的分隔符
Constructor:
File(String pathname) //pathname为路径+文件名或者文件名
File(String parent, String child) //parent为路径,child为文件名
Method:
访问文件名相关的方法:
String getName() //最后一级的名称,无论目录或文件
String getPath() //返回全名,无论目录或文件
File getAbsoluteFile()
String getAbsolutePath() //返回绝对路径
String getParent() //返回上一级,无论目录或文件
boolean renameTo(File newName)
文件检测相关方法:
boolean exists() //文件或目录是否存在
boolean canWrite()
boolean canRead()
boolean isFile() //是否是文件
boolean isDirectory() //是否是目录
boolean isAbsolute() //是否是绝对路径
获取常规文件信息:
long lastModified()
long length()
文件操作相关方法:
boolean createNewFile() //如果已存在,不会覆盖,返回false
boolean delete() //不走回收站
static File createTempFile(String prefix, String suffix) //在默认临时目录创建空文件
void deleteOnExit() //注册一个删除钩子,Java虚拟机退出时删除,保证程序出现异常,文件仍会被删除
目录操作相关方法:
boolean mkdir() //创建目录,但不可以创建多级目录
boolean mkdirs() //可以创建多级目录
String[] list() //列出File对象的所有子文件和路径名,返回String数组
String[] list(FilenameFilter filter) //
File[] listFiles() //列出File对象的所有子文件和路径,返回File数组
File[] listFiles(FileFilter filter) //过滤出File对象的子文件和路径,返回File数组
static File[] listRoots() //列出系统所有的根路径
Windows的路径分隔符使用反斜线(\),而Java程序中的反斜线标识转义字符,所以如果需要在Windows中使用反斜线,应该用两条反斜线(\\),或者直接使用斜线,Java程序支持将斜线当成平台无关的路径分隔符
文件过滤器
在File的list()方法中可以接收一个实现FilenameFilter接口实例的参数
FilenameFilter接口里有且只有一个accept(File dir, String name)方法,该方法会迭代file目录下的文件及文件夹,满足条件返回true时,会存入数组中
public static void main(String[] args)
{
File file = new File("r:/");
String[] filenames = file.list(new FilenameFilter(){
@Override
public boolean accept(File dir, String name)
{
return name.endsWith(".java");
}
});
for(String filename : filenames)
{
System.out.println(filename);
}
}
字节流和字符流
字节流和字符流的区别非常简单,用法几乎一样,区别在于所操作的数据单元不同:
字节流操作的最小数据单元是8位的字节
字符流操作的最小数据单元是16位(GBK编码两个字节表示一个字符)的字符
字节流基类:InputStream和OutputStream
字符流基类:Reader和Writer
字符流都有编码,没有指定时使用的是系统默认编码
编码集
ASCII:(American Standard Code for Information Interchange,美国信息互换标准代码)
拉丁字母--二进制码:一个字母占一个字节中的7位
ISO8859-1:欧洲码表
GB2312:共收入汉字6763个和非汉字图形字符682个
简体中文--二进制码:一个字符占两个字节
GBK:GB2312的扩展(K),共收录汉字21003个、符号883个,并提供1894个造字码位,简、繁体字融于一库
简体、繁体中文--二进制码:一个字符占两个字节
Big5:台湾、香港与澳门地区使用的繁体中文字符集,由台湾五大厂商共同制定
繁体中文--二进制码
Unicode:
Unicode是编码规范,目前实际实现的Unicode编码主要有三种:UTF-8、UCS-2、UTF-16,三种Unicode字符集之间可以按照规范进行转换
最初的Unicode编码是固定长度的,2个字节表示一个字符,但2^16=65535个字符显然远远不够。Unicode4.0定义了一组附加字符编码,使用4个字节表示一个字符
UTF-8(Unicode Transformation Format)是一种8位的Unicode字符集,编码长度可变,兼容ASCII字符集,每个汉字使用3个字节表示
UCS-2(Universal Character Set)是固定长度为16位的Unicode字符集,UCS-2只支持Unicode3.0,所以不支持附加字符
UTF-16是16位的Unicode字符集,兼容UCS-2和附加字符
JVM里的char、String的默认编码是Unicode,即在JVM里出现的所有char、String均是Unicode编码
import java.io.*;
/**
阿
Unicode: 963F 1001 0110 0011 1111
GBK: B0A2 1011 0000 1010 0010
demo.txt文件中内容:
阿
*/
class CharsetTest
{
public static void main(String[] args) throws Exception
{
unicodeRead();
gbkRead();
}
public static void unicodeRead() throws Exception
{
System.out.println("--------Unicode-------------");
//读取到JVM中的字符(字符串)均会使用Unicode编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("demo.txt"), "gbk");
int num = 0;
while((num = isr.read()) != -1)
{
System.out.println(num);
System.out.println(Integer.toBinaryString(num));
}
}
public static void gbkRead() throws Exception
{
System.out.println("--------GBK-----------------");
//直接读取字节数据,没有编码转换过程
FileInputStream fis = new FileInputStream("demo.txt");
int num = 0;
while((num = fis.read()) != -1)
{
System.out.println(num);
System.out.println(Integer.toBinaryString(num));
}
}
}
InputStream与Reader
InputStream和Reader是所有输入流的基类,都是抽象类,本身并不能创建实例来执行输入
但它们将成为所有输入流的模版,所以它们的方法是所有输入流都可以使用的方法
InputStream里包含如下三个方法:
int read() //读取1个字节的数据。前面补24个0,返回32位的int值,当到达流末尾时返回-1
int read(byte[] b) //读取最大b.length个字节的数据,并存储在字节数组b中,返回实际读取的字节数,到达流末尾返回-1
int read(byte[] b, int off, int len) //读取最多len长度的字节,放入b中,并从off位置开始存放,返回实际读取的字节数,到达流末尾返回-1
Reader里包含如下三个方法:
int read() //读取1个字符。前面补16个0,返回32位的int值,当到达流末尾时返回-1
int read(char[] cbuf)
int read(char[] cbuf, int off, int len)
OutputStream与Writer
OutputStream包含的方法:
void write(int c) //输出一个字节的数据(c的最低8位)
void write(byte[] buf) //将字节数组输出到输出流中(几乎用不到)
void write(byte[] buf, int off, int len) //从off开始到len的长度,输出到输出流中(最常用)
void flush() //只有写数据才需要刷新流,字节流可以不用刷新
Writer包含的方法:
void write(int c) //输出一个字符(c的低16位)
void write(char[] buf)
void write(char[] buf, int off, int len)
void write(String str)
void write(String str, int off, int len)
void flush() //只有写数据才需要刷新流
FileInputStream与FileOutputStream
Constructor-FileOutputStream
FileOutputStream(File file, boolean append) //append为true时,从文件末尾追加内容
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
使用字节流复制音乐文件
*/
class FileOutputStreamTest
{
public static void main(String[] args) throws IOException
{
FileInputStream fis = null;
FileOutputStream fos = null;
try
{
fis = new FileInputStream("r:/0.mp3");
fos = new FileOutputStream("r:/1.mp3");
//创建1M大小的容器,用于存放读取的字节数据
byte[] bbuf = new byte[1024*1024];
//实际读取的字节数
int hasRead = 0;
//循环读取
while((hasRead = fis.read(bbuf)) != -1)
{
//写入容器中实际读取到的数据
fos.write(bbuf, 0, hasRead);
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if(fis != null)
{
fis.close();
}
if(fos != null)
{
fos.close();
}
}
}
}
FileReader与FileWriter
FileReader是InputStreamReader的子类,FileWriter是OutputStreamWriter的子类。即是转换流的子类
FileReader与FileWriter均使用系统默认的编码集,不可以指定编码集(转换流可以指定编码集)
Constructor:FileWriter
FileWriter (String filename, boolean append) //append如果为true,在创建FileWriter对象时不会清空原有文件内容,从而实现了在文件末尾处续写内容
import java.io.FileWriter;
import java.io.IOException;
/**
FileWriter的使用
*/
class FileWriterTest
{
public static void main(String[] args) throws IOException
{
//创建一个FileWriter对象,该对象初始化就要明确被操作的文件,如果文件已存在则覆盖
FileWriter fw = new FileWriter("r:/demo.txt");
//写入到内存中,并没有写入到文件
fw.write("abced");
//刷新内存中的数据到文件
fw.flush();
//关闭FileWriter流
fw.close();
}
}
字符缓冲流:BufferedReader与BufferedWriter
BufferedReader是Reader的子类
BufferedWriter是Writer的子类
BufferedReader中注意如下方法:
String readLine() //读取一行数据,当遇到换行(\n)或回车(\r)或(\r\n)时,则认为所读取的数据为一行,这些行结束标记决定读取到哪里为止。如果读取的是一个文件,文件末尾的标记也可以作为行结束标记
BufferedWriter中注意如下方法:
其中所有的write方法,都必须flush()刷新后才会输出
void newLine() //跨平台的换行
注意:
如果BufferedWriter流输出的数据将由readLine()读取,则需要结束标记和刷新才可以被读取到
bw.write("写出数据");
bw.newLine();
bw.flush();
BufferedReader和BufferedWriter只能包装字符流,如果要包装字节流,需要先通过转换流转换
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
/**
从bufferedreader.txt一行行的读取并写入到bufferedwriter.txt中
*/
class BufferedTest
{
public static void main(String[] args) throws Exception
{
BufferedReader br = new BufferedReader(new FileReader("r:/bufferedreader.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("r:/bufferedwriter.txt"));
String buf = null;
while((buf = br.readLine()) != null) //readLine返回该行内容的字符串,不包含任何行终止符
{
bw.write(buf);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
}
打印流:PrintStream与PrintWriter
打印流可以将各种数据类型的数据原样打印
字节打印流(PrintStream)在OutputStream体系下,是FilterOutputStream的子类
字符打印流(PrintWriter)在Writer体系下,是Writer的子类
Constructor:
PrintStream构造函数可以接收的参数类型(即目的地):
1,File对象。File //如new PrintStream(new File("r:/a.txt"));
2,字符串路径。String //如new PrintStream("r:/a.txt");
3,字节输出流。OutputStream //如new PrintStream(new OutputStream("r:/a.txt"), true); //true为自动刷新
PrintWriter构造函数可以接收的参数类型(即目的地):
1,File对象。File //同上
2,字符串路径。String //同上
3,字节输出流。OutputStream //同上
4,字符输出流。Writer //同上
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
/**
输入什么就打印出什么
*/
class PrintTest
{
public static void main(String[] args) throws Exception
{
//标准键盘输入流被BufferedReader包装
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//打印到System.out(标准输出设备)
PrintWriter pw = new PrintWriter(System.out, true);
String str = null;
while((str = br.readLine()) != null)
{
if("over".equals(str))
break;
pw.println(str);
}
br.close();
pw.close();
}
}
转换流:InputStreamReader与OutputStreamWriter
InputStreamReader是Reader子类,OutputStreamWriter是Writer子类
转换流对字节输入流进行包装,同时可以被缓存流包装以提高效率
InputStreamReader:将字节输入流转换成指定字符集(不指定则为默认字符集)的字符输入流
OutputStreamWriter:将字符输出流转换成指定字符集的(不指定则为默认字符集)字节输出流
Java中System.in代表标准输入设备(键盘),键盘输入内容都是文本内容,所以我们可以使用InputStreamReader将其转化为字符输入流
普通Reader读取输入内容时依然不方便,将Reader再次包装成BufferedReader,BufferedReader的readLine方法可以一次读取一行内容
import java.io.*;
/**
转换流
*/
class InputStreamReaderTest
{
public static void main(String[] args) throws Exception
{
//System.in返回的是InputStream的子类实例
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
String buf = null;
while((buf = br.readLine()) != null)
{
if("exit".equals(buf))
{
System.exit(1);
}
bw.write(buf);
bw.newLine();
bw.flush();
}
br.close();
}
}
序列流:SequenceInputStream
把多个输入流合并成一个输入流
Constructor:
SequenceInputStream(Enumeration<? extends InputStream> e)
SequenceInputStream(InputStream s1, InputStream s2)
import java.io.*;
import java.util.*;
/**
SequenceInputStream
*/
class SequenceInputStreamTest
{
public static void main(String[] args) throws Exception
{
Vector<InputStream> v = new Vector<InputStream>();
v.add(new FileInputStream("r:/1.txt"));
v.add(new FileInputStream("r:/2.txt"));
v.add(new FileInputStream("r:/3.txt"));
Enumeration<InputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("r:/4.txt");
byte[] buf = new byte[1024];
int len = 0;
while((len = sis.read(buf)) != -1)
{
fos.write(buf, 0, len);
}
sis.close();
fos.close();
}
}
对象流:ObjectInputStream与ObjectOutputStream
如果需要将某个对象保存到磁盘或者通过网络传输,这个类应该实现Serializable接口或者Externalizable接口
使用Serializable来显示序列化很简单,只需实现该接口,无需实现任何方法,一旦某个类实现了Serializable接口,该类的对象就是可序列化的
Serializable这样的接口称为标记接口
import java.io.*;
/**
对象序列化
*/
class ObjectSerializable
{
public static void main(String[] args) throws Exception
{
writeObj(); //把一个对象写入文件
readObj(); //从文件中读取对象
}
public static void writeObj() throws Exception
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("r:/obj.txt"));
oos.writeObject(new Person("lisi", 22));
oos.close();
}
public static void readObj() throws Exception
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("r:/obj.txt"));
Person p = (Person)ois.readObject();
System.out.println(p);
ois.close();
}
}
class Person implements Serializable
{
//如果不指定UID,改变类中的成员,UID会产生变化,就无法读取以前保存的对象。指定UID,就没有问题
public static final long serialVersionUID = 42L;
private String name;
private int age;
Person(String name, int age)
{
this.name = name;
this.age = age;
}
public String toString()
{
return name+"::"+age;
}
}
管道流:PipedInputStream与PipedOutputStream
输出流和输入流建立连接后,输出流的数据直接由输入流接受,通常结合线程使用
建立连接的两种方式:
1)构造方法
2)in.connect(out)
import java.io.*;
/**
管道流
*/
class PipedStreamTest
{
public static void main(String[] args) throws Exception
{
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
in.connect(out); //管道连通
Read r = new Read(in);
Write w = new Write(out);
new Thread(r).start(); //读取数据
new Thread(w).start(); //写出数据
}
}
class Read implements Runnable
{
private PipedInputStream in;
Read(PipedInputStream in)
{
this.in = in;
}
public void run()
{
try
{
byte[] buf = new byte[1024];
int len = 0;
while((len = in.read(buf)) != -1)
{
System.out.println(new String(buf, 0, len));
}
in.close();
}
catch(Exception e)
{
}
}
}
class Write implements Runnable
{
private PipedOutputStream out;
Write(PipedOutputStream out)
{
this.out = out;
}
public void run()
{
try
{
out.write("hello hello".getBytes());
out.close();
}
catch(Exception e)
{
}
}
}
任意访问文件:RandomAccessFile
该类不是IO体系中子类,而是直接继承Object,但它是IO包中成员,因为它具备读和写的功能
内部封装了一个大型byte数组,而且通过指针对数组的元素进行操作
可以通过long getFilePointer()获取指针位置
同时可以通过void seek(long pos)改变指针的位置
其实完成读写的原理就是内部封装了字节输入流和字节输出流
import java.io.RandomAccessFile;
/**
RandomAccessFile
*/
class RandomAccessFileDemo
{
public static void main(String[] args) throws Exception
{
writeFile();
readFile();
writeFile2();
}
public static void writeFile() throws Exception
{
//读写模式
RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
raf.write("张三".getBytes());
raf.writeInt(97);
}
public static void readFile() throws Exception
{
//只读模式
RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");
//设置指针位置
raf.seek(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println(name);
System.out.println(age);
}
public static void writeFile2() throws Exception
{
//读写模式
RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
//设置指针位置
raf.seek(8*3);
raf.write("周期".getBytes());
raf.write(54);
raf.close();
}
}
字节数组流:ByteArrayInputStream和ByteArrayOutputStream
ByteArrayInputStream的源是数组,从数组中读取数据
ByteArrayOutputStream的目的是内部封装的可变长度数组
这两个流都是对数组进行操作,所有数据都存储在内存中,没有任何底层资源访问(例如创建文件),所以不需要关闭流,也不会产生任何IOException
Method: ByteArrayOutputStream
byte[] toByteArray() //返回存储的字节数组(有效数据)
import java.io.*;
/**
把文件存入数组
源:文件
目的:数组
*/
class ByteArrayTest
{
public static void main(String[] args) throws Exception
{
byte[] context = new ByteArrayTest().getBytes("r:/demo.txt");
System.out.println(new String(context));
}
//接收一个文件路径,返回字节数组
public byte[] getBytes(String src) throws Exception
{
InputStream is = new FileInputStream(src);
ByteArrayOutputStream ba = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while((len = is.read(buf)) != -1)
{
ba.write(buf, 0, len);
}
return ba.toByteArray();
}
}
---------------------- ASP.Net+Android+IOS开发</a>、 .Net培训、期待与您交流! ----------------------