IO基礎到加強
基礎篇
一、一些基礎知識概念
1、文件的邏輯結構
流式文件
記錄式文件
2、文件的存取方法
順序存取
隨機存取
3、文件的使用
操作接口
應用程序接口
4、流的定義和作用
流的定義、方向性和讀/寫操作
流採用緩衝區技術
流的作用:簡單的說就是控制文件的輸入和輸出
5、流的存在
通過這個圖,就可以很好的理解輸入流和輸出流,它們的命名是以程序爲參展點,寫進程序來,就是要用輸入流,寫出程序(寫到文件中)就是要用輸出流。
二、輸入、輸出流
主要分爲兩大類:字節流和字符流
1、字節流
(1)InputStream 抽象字節輸入流類
public abstract class InputStream extends Object implements Closeable
{
public abstract int read() throws IOException; //返回讀取的一個字節,抽象方法
public int read(byte[] b) throws IOException
//從輸入流中讀取若干字節到指定緩衝區,返回實際讀取的字節數
public void close() throws IOException {} //關閉輸入流,空方法
}
a、文件字節輸入流 FileInputSream類
public class FileInputStream extends InputStream
{
public FileInputStream(String name) throws FileNotFoundException
public FileInputStream(File file) throws FileNotFoundException
}
b、數據字節輸入流 DataInputStream類
public class DataInputStream extends FilterInputStream implements DataInput
{
public DataInputStream(InputStream in) //構造方法
public final short readShort() throws IOException
public final byte readByte() throws IOException
public final int readInt() throws IOException //讀取整型
public final long readLong() throws IOException
public final float readFloat() throws IOException
public final double readDouble() throws IOException
public final char readChar() throws IOException //讀取字符
public final boolean readBoolean() throws IOException
}
c、對象字節輸入流 ObjectInputStream類
public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants
{
public ObjectInputStream(InputStream in) throws IOException //構造方法
public final Object readObject() throws IOException, ClassNotFoundException //讀取一個對象
}
(2)OuputStream 抽象字節輸出流類
public abstract class OutputStream extends Object implements Closeable, Flushable
{
public abstract void write(int b) throws IOException; //寫入一個字節,抽象方法
public void write(byte[] b) throws IOException //將緩衝區中的若干字節寫入輸出流
public void flush() throws IOException {} //立即傳輸
public void close() throws IOException {} //關閉輸出流,空方法
}
a、文件字節輸出流 FileOutputStream類
public class FileOutputStream extends OutputStream
{
public FileOutputStream(String name) throws FileNotFoundException
public FileOutputStream(File file) throws FileNotFoundException
public FileOutputStream(String name, boolean append) throws FileNotFoundException
}
b、數據字節輸出流 DataOutputStream類
public class DataOutputStream extends FilterOutputStream implements DataOutput
{
public DataOutputStream(OutputStream out) //構造方法
public final void writeByte(int v) throws IOException
public final void writeShort(int v) throws IOException
public final void writeInt(int v) throws IOException //寫入一個整型
public final void writeLong(long v) throws IOException
public final void writeFloat(float v) throws IOException
public final void writeDouble(double v) throws IOException
public final void writeChar(int v) throws IOException //寫入一個字符
public final void writeBoolean(boolean v) throws IOException
public final void writeChars(String s) throws IOException //寫入一個字符串
public final int size() //返回實際寫入的字節數
}
c、對象字節輸出流 ObjectOutputStream類
public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants
{
public ObjectOutputStream(OutputStream out) throws IOException //構造方法
public final void writeObject(Object obj) throws IOException //寫入一個對象
}
(3)管道字節流
a、PipedInputStream類
b、PipedOutputStream類
PipedInputStream in = new PipedInputStream();
try
{
PipedOutputStream out= new PipedOutputStream(in);
}
catch(IOException ioe) {}
用這個做發牌器就很方便:2、字符流
(1)抽象字符流
a、Reader類
public abstract class Reader extends Object implements Readable, Closeable
{
public int read() throws IOException
public int read(char cbuf[]) throws IOException
abstract public int read(char cbuf[], int off, int len) throws IOException;
abstract public void close() throws IOException;
}
b、Writer類
public abstract class Writer implements Appendable, Closeable, Flushable
{
public void write(int c) throws IOException
public void write(char[] cbuf) throws IOException
public void write(String str) throws IOException //將字符串寫入輸出流
public Writer append(CharSequence csq) throws IOException
public Writer append(char c) throws IOException
public abstract void flush() throws IOException //將緩衝區內容寫入輸出流
public abstract void close() throws IOException
}
(2)文件字符流
a、FileReader類
public class FileReader extends InputStreamReader
{
public FileReader(String fileName) throws FileNotFoundException //構造方法
public FileReader(File file) throws FileNotFoundException
}
b、 FileWriter類
public class FileWriter extends OutputStreamWriter
{
public FileWriter(String fileName) throws IOException //構造方法
public FileWriter(String fileName, boolean append) throws IOException
public FileWriter(File file) throws IOException
public FileWriter(File file, boolean append) throws IOException
}
(3)緩衝字符流
a、BufferedReader類
public class BufferedReader extends Reader
{
public BufferedReader(Reader in) //構造方法
public String readLine() throws IOException //讀取一行字符串,輸入流結束時返回null
}
b、BufferedWriter類
public class BufferedWriter extends Writer
{
public BufferedWriter(Writer out) //構造方法
public BufferedWriter(Writer out, int sz) //sz指定字符緩衝區長度
public void newLine() throws IOException //寫入一個換行符
}
3、文件操作
(1)文件操作類
a、File類的構造方法
public class File extends Object implements Serializable, Comparable<File>
{
public File(String pathname)
public File(String parent, String child)
public File(File parent, String child)
}
例如:
File file = new File("myfile.txt");
File dir = new File(".",""); //創建一個目錄文件對象,表示當前目錄
File dir = new File("C:","");
b、File類提供的方法public String getName() //返回文件名,不包含路徑名
public String getPath() //返回相對路徑名,包含文件名
public String getAbsolutePath() //返回絕對路徑名,包含文件名
public String getParent() //返回父文件對象的路徑名
public File getParentFile() //返回父文件對象
(2)文件過濾器接口
a、FileFilter和FilenameFilter接口
public interface FileFilter
{
public boolean accept(File pathname)
}
public interface FilenameFilter
{
public boolean accept(File dir, String name)
}
b、獲得文件列表時使用過濾器
public String[] list(FilenameFilter filter) //過濾顯示文件清單
public File[] listFiles(FilenameFilter filter)
public File[] listFiles(FileFilter filter)
(3)文件對話框組件
a、JFileChooser類
public class JFileChooser extends JComponent implements Accessible
{
public static final int APPROVE_OPTION = 0; //單擊“打開”或“保存”按鈕
public static final int CANCEL_OPTION = 1; //單擊“撤消”按鈕
public static final int ERROR_OPTION = -1; //出錯
public JFileChooser()
public JFileChooser(String currentDirectoryPath) //初始路徑
public JFileChooser(File currentDirectory)
public void setFileFilter(FileFilter filter) //設置文件過濾器
public int showOpenDialog(Component parent) throws HeadlessException
//顯示打開文件對話框
public int showSaveDialog(Component parent) throws HeadlessException
//顯示保存文件對話框
public File getSelectedFile() //返回選中文件
}
b、JFileChooser的文件過濾器
public abstract class FileFilter extends Object
{
public abstract boolean accept(File f)
//過濾操作,f指定待過濾文件
public abstract String getDescription() //文件類型描述字符串
}
ex
import java.io.File;
import java.io.FilenameFilter;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class DirFilter implements FilenameFilter{ //2
private String prefix="";
private String extension="";
public DirFilter(String filterstr, File dir) {
filterstr = filterstr.toLowerCase();
//取前綴
int i= filterstr.indexOf('*');
if(i>0){
this.prefix = filterstr.substring(0,i);
}
//取後綴
int j= filterstr.lastIndexOf('.');
this.extension = filterstr.substring(j+1);
if(this.extension.equals("*")){
this.extension="";
}
System.out.println(dir.getAbsolutePath()+"目錄中,"+"的文件如下:");
String fileNames[] = dir.list(this); //1
for(String fName:fileNames){
System.out.println(fName);
}
}
public static void main(String[] args) {
new DirFilter("*.Java",new File(".","src/cn/hncu/inOut/p29"));
JFileChooser jf = new JFileChooser();
jf.showOpenDialog( new JFrame() );
}
public boolean accept(File dir, String fileName) {
fileName = fileName.toLowerCase();
return fileName.startsWith(this.prefix) && fileName.endsWith(extension);
}
}
(4)隨機存取文件類
public class RandomAccessFile extends Object implements DataOutput, DataInput, Closeable
{
public RandomAccessFile(String name, String mode) throws FileNotFoundException
public RandomAccessFile(File file, String mode) throws FileNotFoundException
public final int readInt() throws IOException
//讀一個整數類型值,當讀到文件尾時,拋出EOFException異常
public final void writeInt(int v) throws IOException //寫入一個整型值
public long length() throws IOException //返回文件長度
public long getFilePointer() throws IOException //獲取文件指針位置
public void seek(long pos) throws IOException //設置文件指針位置
public void close() throws IOException //關閉文件
}
4、各種輸入/輸出流及其讀/寫方法
數據字節流ex
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class MyDataInOutputStream {
public static void main(String[] args) {
// writeToFile();
readFromFile();
}
private static void writeToFile() {
OutputStream fout = null;
DataOutputStream dout = null;
try {
fout = new FileOutputStream("d:\\ex\\a\\a.txt");//目錄必須已存在
dout = new DataOutputStream(fout);
for(int i=1;i<=100;i++){
dout.writeInt(i);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (Exception e) {
}finally{
try {
fout.close();
dout.close();
} catch (IOException e) {
System.out.println("文件無法關閉");
}
}
}
private static void readFromFile() {
FileInputStream fin = null;
DataInputStream din = null;
try {
fin = new FileInputStream("d:\\ex\\a\\a.txt");
din = new DataInputStream(fin);
while(din.available()>0){
System.out.print( din.readInt() +" ");
}
System.out.println();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (Exception e) {
}finally{
try {
fin.close();
din.close();
} catch (IOException e) {
System.out.println("文件無法關閉");
}
}
}
}
對象字節流ex
import java.io.File;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class MyObjectOutputStream extends ObjectOutputStream {
//定義成靜態的好處
private static File f;
public static MyObjectOutputStream newInstance(File file, OutputStream out)
throws IOException {
f = file;//本方法最重要的地方:構建文件對象,是兩個文件對象屬於同一個
return new MyObjectOutputStream(out, f);
}
@Override
protected void writeStreamHeader() throws IOException {
if (!f.exists() || (f.exists() && f.length() == 0)) {
super.writeStreamHeader();
} else {
super.reset();
}
}
public MyObjectOutputStream(OutputStream out, File f) throws IOException {
super(out);
}
}
文件字節流ex
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyFileInOutputStream {
public static void main(String[] args) {
//readFromFile();
writeToFile();
}
private static void readFromFile() {
byte buffer[] = new byte[512];
int num=0;
try {
FileInputStream in = new FileInputStream("D:\\ex\\a\\a.txt");
num = in.read(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
for(int i=0;i<num;i++){
//System.out.print(buffer[i]+" ");
System.out.print((char)buffer[i]+" ");
}
//System.out.println();
}
private static void writeToFile(){
try {
//FileOutputStream out = new FileOutputStream("d:/ex/a/b.dat");//覆蓋
FileOutputStream out = new FileOutputStream("d:/ex/a/b.dat",true);//追加
byte[] buffer = {13,10,97,98,99,100,101,102,49,55};
out.write(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
}
管道字節流(模擬發牌器)ex
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class SendCard {
PipedInputStream[] in;
PipedOutputStream[] out;
int data[][]; //data[n][max/n],保存n個接收線程分別保存的牌
public SendCard(int max, int n) throws IOException{
in = new PipedInputStream[n];
out = new PipedOutputStream[n];
for(int i=0;i<n;i++){
in[i] = new PipedInputStream();
out[i] = new PipedOutputStream(in[i]);
}
Sender s = new Sender(out,max);
s.start();
data = new int[n][max/n];
for(int i=0; i<n; i++){
new Receiver(in[i],data[i]).start();
}
}
public void print(){
System.out.println();
for(int i=0;i<data.length; i++){
System.out.print("Receiver"+(i+1)+": ");
for(int j=0; j<data[i].length; j++){
System.out.print(data[i][j]+" ");
}
System.out.println();
}
}
public static void main(String[] args) {
try {
SendCard sc = new SendCard(52,4);
Thread.sleep(1);
sc.print();
} catch (Exception e) {
e.printStackTrace();
}
}
}
結果:Sender:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
Receiver1: 1 5 9 13 17 21 25 29 33 37 41 45 49
Receiver2: 2 6 10 14 18 22 26 30 34 38 42 46 50
Receiver3: 3 7 11 15 19 23 27 31 35 39 43 47 51
Receiver4: 4 8 12 16 20 24 28 32 36 40 44 48 52
文件拷貝ex
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopyStream {
public static void main(String[] args) {
//fileCopy0("b.dat","d:/ex/a/","d:/ex/b/");
//fileCopy1("b.dat","d:/ex/a/","d:/ex/b/");
//fileCopy2("b.dat","d:/ex/a/","d:/ex/b/");
fileCopy3("1.mp3","d:/ex/a/","d:/ex/b/");
//fileCopy3("c.mp3","d:/ex/a/","d:/ex/b/");
//fileCopy3("d.txt","d:/ex/a/","d:/ex/b/");
}
private static void fileCopy0(String fileName, String dir1,String dir2){
try {
FileInputStream in = new FileInputStream(dir1+fileName);
FileOutputStream out = new FileOutputStream(dir2+fileName);
byte[] buffer = new byte[512];
in.read(buffer);
out.write(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
}
}
//學習關流
private static void fileCopy1(String fileName, String dir1,String dir2){
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(dir1+fileName);
out = new FileOutputStream(dir2+fileName);
byte[] buffer = new byte[512];
in.read(buffer);
out.write(buffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
}finally{
try {
in.close();
out.close();
} catch (IOException e) {
throw new RuntimeException("文件無法關閉");
}
}
}
//能夠拷貝大文件
private static void fileCopy2(String fileName, String dir1,String dir2){
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(dir1+fileName);
out = new FileOutputStream(dir2+fileName);
byte[] buffer = new byte[512];
int num = 0;
do{
num = in.read(buffer);
out.write(buffer,0,num);
}while(num>=0);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
in.close();
out.close();
} catch (IOException e) {
throw new RuntimeException("文件無法關閉");
}
}
}
//能夠拷貝大文件
private static void fileCopy3(String fileName, String dir1,String dir2){
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(dir1+fileName);
out = new FileOutputStream(dir2+fileName);
byte[] buffer = new byte[512];
int num=0;
while(in.available()>0){
num = in.read(buffer);
//最簡單的加密
for(int i=0;i<num;i++){
buffer[i] = (byte)(buffer[i]+1);
}
out.write(buffer,0,num);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
}finally{
try {
in.close();
out.close();
} catch (IOException e) {
throw new RuntimeException("文件無法關閉");
}
}
}
}
字符流ex
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class MyReaderWriter {
private static final String LINE_SEPARATOR = System
.getProperty("line.separator");
public static void main(String[] args) {
try {
// writeToFile();
//readFromFile();
copyFile();
} catch (IOException e) {
e.printStackTrace();
}
// writeToFile2();
}
private static void writeToFile() throws IOException {
FileWriter fw = new FileWriter("aw.txt");
fw.write("abcdkk");
// fw.write("\n");
// fw.write("\r\n");
fw.write(LINE_SEPARATOR);
fw.write("城市海陸空");
// fw.flush();
fw.close();
}
/* 用字符流寫文件,模板 */
private static void writeToFile2() {
FileWriter fw = null;
try {
fw = new FileWriter("aw.txt");
fw.write("abcdkk");
fw.write(LINE_SEPARATOR);
fw.write("城市海陸空");
fw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
throw new RuntimeException("關閉失敗!");
}
}
}
}
private static void readFromFile() throws IOException {
FileReader fr = new FileReader("aw.txt");
//char c = (char) fr.read();
//System.out.println(c);
char[] buffer = new char[1024];
int num;
while((num=fr.read(buffer))!=-1){
System.out.println( new String(buffer,0,num) );
}
}
//用字符流拷貝,是不能拷非文本文件,會失真!
private static void copyFile() throws IOException{
FileReader fr = new FileReader("d:/ex/a/a.txt");
FileWriter fw = new FileWriter("d:/ex/a/b.txt");
char[] buffer = new char[512];
int len=0;
while((len=fr.read(buffer))!=-1){
fw.write(buffer, 0, len);
}
fw.close();
fr.close();
}
}
強化篇
一、RandomAccessFile
1、隨機訪問文件,自身具備讀寫的方法
new RandomAccessFile()之後,若文件不存在會自動創建,存在則不創建。——該類其實內部既封裝了字節輸入流,又封裝了字節輸出流。
該類若用write()方法寫整數,每次只寫它的最後一個字節。而採用writeInt()方法,則可把一個整數完整地寫入。
2、通過skipBytes(int x),seek(int x)來達到隨機訪問
通過seek方法設置數據的指針就可以實現對文件數據的隨機讀寫。InputStream中的skip()方法只能從頭往後跳,不能反向;而seek()方法可雙向隨便定位。
3、數據修改方面的特點
用RandomAccessFile類可以實現數據的修改,當然文件中的數據一般要有規律,以方便在編程時能夠進行定位,讓數據寫對地方。 而用“流”實現數據修改時,則通常需要把數據從流讀到數組當中,在數組中進行數據修改,然後再把修改後的數組
再重新寫到流中。
/*
* 用IO流讀取數據時,遊標是會自動走的。
* 而RandomAccessFile的遊標是不會自動向前移動的,要自己控制的
*
* 1)用RandomAccessFile類訪問數據表記錄的速度比Object流更快,因爲後者查找匹配的是一個對象
* 2)InputStream類中的skip()方法只能從頭往後跳,不能反向。而RandomAccessFile類中的seek()定位,可以雙向隨意定位。
* 3)如果存儲的數據有規律(比如,數據庫表中的數據),應該採用RandomAccessFile
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class RandomAcessFileDemo4 {
public static void main(String[] args) {
write2File();
readFromFile();
}
private static void write2File() {
RandomAccessFile rf = null;
try {
rf = new RandomAccessFile("d:/ex/a/r4.txt", "rw");
for(int i=0;i<10;i++){
rf.writeDouble(3.14f*i);
}
rf.seek(16);//絕對定位
rf.writeDouble(0);
rf.seek(rf.length());
for (int i = 1; i <= 5; i++) {
rf.writeInt(15*i);
rf.writeByte(5*i);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (rf != null) {
try {
rf.close();
} catch (IOException e) {
throw new RuntimeException("關流失敗");
}
}
}
}
private static void readFromFile() {
RandomAccessFile rf = null;
try {
rf = new RandomAccessFile("d:/ex/a/r4.txt", "r");
// long pointer = 0;//自己控制遊標
// long len = rf.length();
// //rf.skipBytes(2);//寫入的是浮點,不需要跳
// while (pointer < len) {
// double d = rf.readDouble();
// System.out.println(d);
// pointer = rf.getFilePointer();
// }
// rf.seek(48);
// double d = rf.readDouble();
// System.out.println(d);
rf.seek(85);
int x = rf.readInt();
System.out.println(x);
} catch (IOException e1) {
e1.printStackTrace();
} finally {
if (rf != null) {
try {
rf.close();
} catch (IOException e) {
throw new RuntimeException("關流失敗");
}
}
}
}
}
二、序列化
1、序列化
將一個對象存放到某種類型的永久存儲器上稱爲保持。如果一個對象可以被存放到磁盤或磁帶上,或者可以發送到另外一臺機器並存放到存儲器或磁盤上,那麼這個對象就被稱爲可保持的。(在Java中,序列化、持久化、串行化是一個概念。)
java.io.Serializable接口沒有任何方法,它只作爲一個“標記者”,用來表明實現了這個接口的類可以考慮串行化。類中沒有實現Serializable的對象不能保存或恢復它們的狀態。
2、對象圖
當一個對象被串行化時,只有對象的數據被保存;方法和構造函數不屬於串行化流。如果一個數據變量是一個對象,那麼這個對象的數據成員也會被串行化。樹或者對象數據的結構,包括這些子對象,構成了對象圖。
3、瞬時 transient
防止對象的屬性被序列化。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TestSerializable {
public static void main(String[] args) {
//序列化---寫(輸出)到永久存儲器
FileOutputStream fout = null;
try {
fout = new FileOutputStream("a.txt");
ObjectOutputStream out = new ObjectOutputStream(fout);
//Address類必須要實現Serializable接口,否則不能序列化
// out.writeObject(new Address("aa",11,"12345678908"));
// out.writeObject(new Address("bb",22,"12345888888"));
// out.writeObject(new Address("cc",33,"12345666666"));
// out.writeObject(new Address("dd",44,"12345777777"));
out.writeObject(new Address(1,"aa",11,"12345678908"));
out.writeObject(new Address(5,"bb",22,"12345888888"));
//線程Thread本身是沒有實現Serializable接口的,因此不能序列化
//Thread t1 = new Thread();
//out.writeObject(t1);
//如果自定義線程類實現了Serializable接口,則可以序列化
MyThread mt1 = new MyThread();
out.writeObject(mt1);
//反序列化----從永久存儲器讀取(輸入)數據
FileInputStream fin = new FileInputStream("a.txt");
ObjectInputStream in = new ObjectInputStream(fin);
System.out.println(in.readObject());
System.out.println(in.readObject());
System.out.println(in.readObject());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally{
if(fout!=null){
try {
fout.close();
} catch (IOException e) {
throw new RuntimeException("關流失敗!");
}
}
}
}
}
class Address implements Serializable{
transient int num; //瞬時變量,不會被序列化
String name;
int age;
String tel;
public Address(int num, String name, int age, String tel) {
this.num = num;
this.name = name;
this.age = age;
this.tel = tel;
}
@Override
public String toString() {
return "Address [num=" + num + ", name=" + name + ", age=" + age
+ ", tel=" + tel + "]";
}
}
class MyThread extends Thread implements Serializable{
}
三、緩衝輸入輸出流(BufferedInputStream和BufferedOutputStream)
方式1:(方案1是最優的)
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("Test.txt") );
方式2:
DataInputStream in = new DataInputStream(
new FileInputStream("Test.txt") );
方式3:
BufferedInputStream in = new BufferedInputStream(
new DataInputStream(
new FileInputStream("Test.java") );
1)有buffer比沒有更快;
2)buffer放在中間層包裝比放在外層更快;
3)按行或按塊操作 比 按字節或字符操作更快(用Object流操作的速度 比 字節字符方式 更快)
4)緩衝區要結合流纔可以使用,在流的基礎上對流的功能進行了增強。
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class BufferedStreamDemo {
public static void main(String[] args) {
try {
//testRead1();
//testRead2();
testRead3();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void testRead1() throws Exception{
long t1 = System.currentTimeMillis();//起始時間
DataInputStream din = new DataInputStream(
new BufferedInputStream(
new FileInputStream("test.xyz")));
String strLine="";
while((strLine=din.readLine())!=null ){
System.out.println(strLine);
}
long t2 = System.currentTimeMillis();//終止時間
System.out.println("case1-time:"+(t2-t1));
}
public static void testRead2() throws Exception{
long t1 = System.currentTimeMillis();//起始時間
DataInputStream din = new DataInputStream(
new FileInputStream("test.xyz"));
String strLine="";
while((strLine=din.readLine())!=null ){
System.out.println(strLine);
}
long t2 = System.currentTimeMillis();//終止時間
System.out.println("case2-time:"+(t2-t1));
}
public static void testRead3() throws Exception{
long t1 = System.currentTimeMillis();//起始時間
BufferedInputStream din = new BufferedInputStream(
new DataInputStream(
new FileInputStream("test.xyz")));
byte bs[] = new byte[din.available()];
din.read(bs);
System.out.println(new String(bs));
long t2 = System.currentTimeMillis();//終止時間
System.out.println("case3-time:"+(t2-t1));
}
}
四、轉換流(InputStreamReader和OutputStreamWriter)
1、轉換流功能1:充當字節流與字符流之間的橋樑
例:需求:模擬英文聊天程序,要求:
(1) 從鍵盤錄入英文字符,每錄一行就把它轉成大寫輸出到控制檯;
(2) 保存聊天記錄到字節流文件。
要求1的設計分析:a)需要從鍵盤接收錄入,得用System.in,它是字節輸入流InputStream;
b)需要處理字符,可以自己把字節強轉成字符,也可以用字符流;
c)需要類似readLine的功能,而這個方法在字符流BufferedReader中有(而且該類有緩衝增速)。
綜上,採用轉換流把字節流轉成字符流處理比較合理,即使用InputStreamReader
要求2的設計分析:
a)需要把字符數據按行保存到字節流文件 ;
b)字符流採用BufferedWriter比較合適,因爲它有newLine方法且能實現高效;
c)字節流文件,得采用FileOutputStream。
綜上,採用轉換流把字符流轉成字節流處理比較合理,即使用OutputStreamWriter
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;
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
//輸入
InputStream in = System.in;
//System.out.println(in.read());
InputStreamReader isr = new InputStreamReader(in);
BufferedReader bufr = new BufferedReader(isr);
//String str =bufr.readLine();
//輸出
FileOutputStream fout = new FileOutputStream("files\\out.txt",true);
OutputStreamWriter osw = new OutputStreamWriter(fout);
BufferedWriter bufw = new BufferedWriter(osw);
//聊天
String line=null;
while( (line=bufr.readLine())!=null){
// if(line.equals("over")){
// break;
// }
if("over".equals(line)){//一個好的習慣:把字符串常量放在前面
break;
}
System.out.println(line.toUpperCase());
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
//關流
bufw.close();
osw.close();
fout.close();
bufr.close();
isr.close();
}
}
2、轉換流功能2:字符編碼轉換
a)採用FileWriter以默認方式編碼
FileOutputStream+默認編碼表
b)採用轉換流以默認方式編碼
OutputStreamWriter + FileOutputStream + 默認編碼表
c)採用轉換流以指定編碼方式編碼
OutputStreamWriter + FileOutputStream +指定編碼表
d)採用轉換流以指定編碼方式解碼
InputStreamReader + FileInputStream +指定編碼表
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class TransStreamDemo2 {
public static void main(String[] args) {
try {
//readTestDecoding();
writeTextEncoding();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void readTestDecoding() throws IOException{
//FileReader fr = new FileReader("files\\utf8.txt");//採用默認編碼表來解碼(而且在MyEclipse中可以更改默認編碼)
//FileReader fr = new FileReader("files\\gbk.txt");
// char cbuf[] = new char[50];
// int len = fr.read(cbuf);
// String str = new String(cbuf,0,len);
// System.out.println(str);
// fr.close();
//通過轉換流解決亂碼
InputStreamReader isr = new InputStreamReader(new FileInputStream("files\\gbk.txt"), "gbk");
//InputStreamReader isr = new InputStreamReader(new FileInputStream("files\\utf8.txt"), "utf-8");
char buf[] = new char[50];
int len2 = isr.read(buf);
String str2 = new String(buf,0,len2);
System.out.println(str2);
isr.close();
}
//輸出流,字符流的編碼解決方案
public static void writeTextEncoding() throws IOException{
//第一種 (使用默認編碼表 )
FileWriter fw = new FileWriter("files\\gbk-1.txt");
fw.write("每天進步一點點...");
fw.close();//內部含flush()的功能
//第二種(相當於 FileOutputStream+默認編碼表 )
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("files\\gbk-2.txt"));
osw.write("每天進步一點點22222...");
osw.close();//內部含flush()的功能
//第三種(既明確字節輸出流,又明確編碼表 )
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream("files\\wutf8-1.txt"),"utf-8");
osw2.write("每天進步一點點22222...");
osw2.close();//內部含flush()的功能
}
}
五、打印流(PrintStream和PrintWriter)
1、打印流的特點
1)只有輸出沒有輸入。PrintStream是字節打印流,PrintWriter是字符打印流。
2)能夠方便地打印各種數據“值表示形式”,提供了一系列的打印功能(只有它有,其它流都沒有。)
3)和其他輸出流不同,它永遠不會拋出IOException異常(構造方法除外),異常內部解決且設置了內部標誌。
4)可創建具有自動刷新的功能,可使用帶換行符的println()方法。
5)(在構造方法中)可以指定字符集編碼的。
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
public class PrintStreamDemo {
public static void main(String[] args) {
/*
try {
printStreamDemo();
} catch (IOException e) {
e.printStackTrace();
}
*/
PrintStream outBak = System.out;
changeOut(null);
for(int i=1;i<=10;i++){
System.out.println(i);
}
changeOut(outBak);
for(int i=100;i<=110;i++){
System.out.println(i);
}
}
public static void printStreamDemo()throws IOException{
PrintStream out = new PrintStream("aa.txt");
//out.write(97);//輸出該整數的最後一個字節 :97
//out.write(353);//只輸出該整數的最後一個字節 : 97 用於計算機內部處理的
out.print(97);//輸出該整數的值的表現形式:'9'和'7' 用於給人看的
//out.print(35378332);
}
/*
void print(int i){
out.write(String.valueOf(i));
}
*/
public static void changeOut(PrintStream out0){
PrintStream out=null;
if(out0!=null){
System.setOut(out0);
}else{
try {
out = new PrintStream("aa2.log");
System.setOut(out);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
2、關於打印流的自動刷新
只有遇到結束字符(換行符)時纔會自動刷新,如在調用其中一個println方法或寫入換行符或字節('\n)時會自動刷新輸出緩衝區。
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
public class PrintWriterDemo {
public static void main(String[] args) throws IOException{
//encodingDemo();
//autoFlushDemo();
autoFlushDemo2();
}
private static void encodingDemo() throws IOException {
//PrintWriter out = new PrintWriter("gbk.txt");//用默認編碼表
//PrintWriter out = new PrintWriter("gbk.txt","utf-8");//指定編碼表
PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream("gbk.txt"),"utf-8"));//要指定編碼表,建議最好採用轉換流,因爲它就是專門用來指定編碼的
out.print("中國人民共和國");
out.close(); //字符輸出流,一定要刷新flush()。close()方法中帶有flush()
}
private static void autoFlushDemo(){
PrintWriter out = new PrintWriter(System.out,true);//(1)默認不自動刷新,因此下面還是要手動寫flush()
out.print("Hello World!");
out.flush();
PrintWriter out2 = new PrintWriter(System.out,true);//(2)默認不自動刷新,因此下面還是要手動寫flush()
out2.print("Hello World2!");//不會自動刷新
out2.print("Hello World2!\n");//還是不會自動刷新
out2.println("Hello World3!");//“會”自動刷新
//println,pringf,format會自動刷新
}
//需求:將鍵盤錄入的英文字符轉成大寫並按行存儲到文件中,且帶自動刷新功能
private static void autoFlushDemo2()throws IOException{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//PrintWriter out = new PrintWriter(new FileWriter("recod.txt"));//默認不帶自動刷新
PrintWriter out = new PrintWriter(new FileWriter("recod.txt"),true);//默認不帶自動刷新
String line = null;
while((line=bufr.readLine())!=null){
if("over".equalsIgnoreCase(line)){
break;
}
//out.write(line.toUpperCase()+"\r\n");
//out.flush();
out.println(line.toUpperCase());
}
}
}
六、序列流、字節數組流
1、SequenceInputStream ——對多個流進行合併
將多個流進行邏輯串聯(合併變成一個流,操作起來很方便,因爲多個源變成了一個源)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.SequenceInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
public class SequenceInputStreamDemo {
public static void main(String[] args) throws IOException{
FileInputStream fis1 = new FileInputStream("filesequences\\seq1.txt");
FileInputStream fis2 = new FileInputStream("filesequences\\seq2.txt");
FileInputStream fis3 = new FileInputStream("filesequences\\seq3.txt");
//需要枚舉對象,通過Collections.enumeration(Collection t)來實現
ArrayList<FileInputStream> v = new ArrayList<FileInputStream>();
v.add(fis1);
v.add(fis2);
v.add(fis3);
Enumeration<FileInputStream> en = Collections.enumeration(v);
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("filesequences\\merge.txt");
byte buf[] = new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1){
fos.write(buf, 0, len);
}
fos.close();
sis.close();
}
}
2、字節數組流
ByteArrayInputStream與ByteArrayOutputStream
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
public class ByteArrayStreamDemo {
public static void main(String[] args) {
ByteArrayInputStream bis = new ByteArrayInputStream("dssd2323232".getBytes());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int ch=0;
while((ch=bis.read())!=-1){
bos.write(ch);
}
System.out.println( bos.toString() );
}
}
七、IO流知識點小結
1、知識點
a、流是用來處理數據的。
b、處理數據時,一定要先明確數據源與數據目的地(數據匯)。
c、數據源可以是文件、鍵盤或者其他流。
d、數據目的地可以是文件、顯示器或者其他流。
e、流只是在幫助數據進行傳輸,並對傳輸的數據進行處理,比如過濾處理、轉換處理等。
2、 IO流體系
使用要點:看頂層(父類共性功能),用底層(子類具體對象)。
命名規律:每個子類的後綴名都是所屬體系的父類的名稱,很容易區分所屬的體系。
而且每一個子類前綴名都是該子類對象的功能體現。
(掌握IO流體系的要點和規律,開發時設計與查找相應的類就容易多了)
八、IO流的操作規律
1、明確源和目的。
源:InputStream Reader 一定是被讀取的。
目的:OutputStream Writer 一定是被寫入的。
2、處理的數據是否是純文本的數據?
是:使用字符流。Reader Writer
否:使用字節流。 InputStream OutputStream
(到這裏,兩個明確確定完,就可以確定出要使用哪個體系。接下來,就應該明確具體這個體系要使用哪個具體的對象。【所謂的看頂層】)
3、明確數據所在的設備。
源設備:
鍵盤(System.in)
硬盤(FileXXX)FileReader FileInputStream
內存(數組)ByteArrayInputStream CharArrayReader StringReader
網絡(Socket)
目的設備:
顯示器(控制檯System.out)
硬盤(FileXXX)FileWriter FileOutputStream
內存(數組)ByteArrayOutputStream CharArrayWriter StringWriter
網絡(Socket)
(到這裏,具體使用哪個對象就可以明確了。【所謂的用底層】)
4、明確是否需要額外功能?
1) 是否需要高效?緩衝區Buffered (字符與字節各兩個)
2) 是否需要轉換?轉換流 InputStreamReader OutputStreamWriter
3) 是否操作基本數據類型? DataInputStream DataOutputStream
4) 是否操作對象(對象序列化)? ObjectInputStream ObjectOutputStream
5) 需要對多個源合併嗎? SequenceInputStream
6) 需要保證數據的表現形式到目的地嗎? PrintStream 或 PrintWriter
(到這裏,具體的設計方案就可以明確了。【套接與功能加強】)
IO流的操作規律之設計方案練習
需求1:複製一個文本文件。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、處理的數據是否是純文本的數據?
源:Reader
目的:Writer
3、明確數據所在的設備。
源:file(硬盤) FileReader fr = new FileReader("a.txt");
目的:file(硬盤) FileWriter fw = new FileWriter("b.txt");
4、明確是否需要額外功能?
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
需求2:複製一個圖片文件。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、處理的數據是否是純文本的數據?
源:Reader
目的:Writer
3、明確數據所在的設備。
源:file(硬盤) FileReader fr = new FileReader("a.txt");
目的:file(硬盤) FileWriter fw = new FileWriter("b.txt");
4、明確是否需要額外功能?
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
需求3:讀取鍵盤錄入,存儲到一個文件中。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、處理的數據是否是純文本的數據?
源:Reader
目的:Writer
3、明確數據所在的設備。
源:file(硬盤) InputStream in = System.in; 原因:必須要將鍵盤錄入的字節轉成字符。需要將字節-->字符的轉換流。InputStreamReader
目的:file(硬盤) FileWriter fw = new FileWriter("b.txt");
4、明確是否需要額外功能?
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("a.txt");
高效:BufferedReader bufr = new BufferedReader( isr);
BufferedWriter bufw = new BufferedWriter( fw );
需求4:讀取一個文本文件,顯示到顯示器上。
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、處理的數據是否是純文本的數據?
源:Reader
目的:Writer
3、明確數據所在的設備。
源:file(硬盤) FileReader fr = new FileReader("a.txt");
目的:顯示器 OutputStream out = System.out; 原因:要將字符數據轉換成字節輸出。輸出轉換流:OutputStreamWriter
4、明確是否需要額外功能?
FileReader fr = new FileReader("a.txt");OutputStreamWriter osw = new OutputStreamWriter(System.out);
高效:BufferedReader bufr = new BufferedReader( fr);
BufferedWriter bufw = new BufferedWriter( osw );
需求5:讀取一個文本文件,將文本按照指定的編碼表UTF-8寫入到另一個文件中
1、明確源和目的。
源:InputStream Reader
目的:OutputStream Writer
2、處理的數據是否是純文本的數據?
源:Reader
目的:Writer
3、明確數據所在的設備。
源:file(硬盤) FileReader fr = new FileReader("a.txt");
目的:file(硬盤) FileOutputStream fout = new FileOutputStream("b.txt")原因:假定輸出時要爲字符數據指定編碼表。轉換流中的參數需要字節流,因此用轉換流:FileOutputStream。
4、明確是否需要額外功能?
FileReader fr = new FileReader("a.txt");OutputStreamWriter osw = new OutputStreamWriter(fout,”utf-8”);
高效:BufferedReader bufr = new BufferedReader( fr);
BufferedWriter bufw = new BufferedWriter( osw );
九、兩大例題
1、文件切割與合併
2、字符串截取
點擊打開鏈接
雖然看上去很多,其實仔細看看也沒什麼,無非是看懂加強片中的八中所講的內容,就可以隨手寫io了。