1. 程式人生 > 實用技巧 >fastDFS檔案上傳實現

fastDFS檔案上傳實現

學習IO流知識梳理:

位元組流

一些注意點:

英文 1位元組

中文 gbk utf-8 2位元組、3位元組

相對路徑———專案下尋找

File

❑ File類:檔案和目錄路徑名的抽象表現形式

❑ 作用:通過File物件實現對檔案或者資料夾的操作 ❑ 常用構造方法:

❑File(String URL)

❑ 常用方法: ❑String getName() --- 獲取當前檔案物件的名字

❑long length() --- 獲取檔案物件的大小 單位:位元組

❑boolean isFile()/isDirectory()--- 判斷檔案/資料夾

❑boolean canRead()/canWrite()--- 判斷檔案可讀/可寫

❑boolean isHidden() --- 判斷file物件是否為隱藏

❑long lastModified() --- 獲取當前file物件最後修改時間

public class TestFile02 {
    public static void main(String[] args) {
//      test01();
//      test02();
        
        File file = new File("A");
        test03(file);
​
    }
​
    private static void test03(File file) {
        
if(file.isDirectory()) { //如果是資料夾,遍歷 File[] files = file.listFiles(); for (File file2 : files) { //繼續判斷檔案型別 test03(file2); } //刪除空的資料夾 file.delete(); }else { //只要是檔案,直接刪除
file.delete(); } } ​ private static void test02() { File file = new File("test01.txt"); System.out.println(file.exists()); if(!file.exists()) { try { file.createNewFile(); //建立檔案 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } File file2 = new File("A"); if(!file2.exists()) { //建立資料夾 // file2.mkdir();//只能建立單層資料夾 file2.mkdirs();//建立多層資料夾 } //刪除檔案或者資料夾 //刪除檔案的時候,不管有沒有內容都會刪除 //刪除資料夾的時候,只能刪除空資料夾 // file.delete(); file2.delete(); //獲取子檔案 File[] files = file2.listFiles(); System.out.println(files); for (File file3 : files) { System.out.println(file3); } } ​ private static void test01() { // 相對路徑:從專案底下去找 // 絕對路徑:從碟符去找 // File file = new File("src\\cn\\goktech\\test02.txt"); File file = new File("D:" + File.separator + "原始碼\\龍巖實訓\\LYSE進階01\\src\\cn\\goktech\\test03.txt"); System.out.println(file); // 獲取絕對路徑 System.out.println(file.getAbsolutePath()); // 判斷檔案是否存在 System.out.println(file.exists()); // 獲取檔名 System.out.println(file.getName()); // 獲取檔案大小 System.out.println(file.length()); // 判斷是否是檔案/資料夾 System.out.println(file.isFile()); System.out.println(file.isDirectory()); // 判斷可讀 System.out.println(file.canRead()); // 判斷可寫 System.out.println(file.canWrite()); // 判斷是否隱藏 System.out.println(file.isHidden()); // 獲取最後的修改時間 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = sdf.format(new Date(file.lastModified())); System.out.println(time); ​ } ​ }

File類常用方法

➢ 常用變數:File.separator –目錄分隔符(/)

➢ 常用方法: • boolean exists() -- 判斷檔案是否存在

• void createNewFile() -- 建立新檔案

• void mkdir()/mkdirs() – 建立新資料夾

• delete() – 刪除檔案或者資料夾

• File[] listFiles() – 獲取當前資料夾下所有的子項,如果當前檔案下為空則返回null值

FileFilter和FilenameFilter

❑ 檔案過濾器 來獲取一個目錄下 滿足條件的部分子選項(即只獲取檔案或只獲取 目錄)

❑ 檔案過濾器更多是被用於listFiles(FileFilter filter)的引數中。

❑ FileFilter介面: public boolean accept(File pathname)

❑ FilenameFilter介面: public boolean accept(File dir, String name)

public class TestFilter03 {
    public static void main(String[] args) {
        File file = new File("D:\\工作\\授課\\龍巖實訓");
//      File[] files = file.listFiles(new FileFilter() {
//          
//          @Override
//          public boolean accept(File pathname) {
////                System.out.println(pathname);
//              return pathname.getName().endsWith(".xlsx");
//          }
//      });
        
        File[] files = file.listFiles(new FilenameFilter() {
            
            @Override
            public boolean accept(File dir, String name) {
//              System.out.println(dir);
//              System.out.println(name);
                return name.endsWith("xlsx");
            }
        });
        
        for (File file2 : files) {
            System.out.println(file2);
        }
    }
​
}

  

RandomAccessFile類

➢ RandomAccessFile支援訪問檔案隨機的讀入和讀取 ➢ 建構函式: • RandomAccessFile(File file , String mode) • RandomAccessFile(File file , String mode) 引數說明: 1、第一個引數:要訪問的檔案物件/檔案路徑 2、第二個引數:讀寫模式(r:只讀模式;rw:可讀可寫) • 常用方法: ◆ read() – 從此檔案中讀取一個數據位元組 ◆ write(int b) – 向此檔案中寫入指定的位元組 ◆ read()和write()都有多個過載的方法,詳見API 寫入字串亂碼- - 轉。g e t B y t e

Byte[] b = new Byte[2];
read(b) 一叢讀取多少
syso.....(new Strng(bt))轉中文

RandomAccessFile類

➢ 利用RandomAccessFile類提供的方法可以進行對檔案指標的操作 ➢ 方法說明: • long getFilePoint():獲取該檔案當前的指標位置 • void seek(long pos):該方法允許我們將指標移動到指定位置 • 常用地方: ◆ 結合多執行緒對檔案進行多點複製(迅雷下載)

public class TestRandomAccessFile04 {
    public static void main(String[] args) {
        
        File file = null;
        RandomAccessFile raf = null;
        try {
            file = new File("test01.txt");
            raf = new RandomAccessFile(file, "rw");
            //寫資料
            raf.write(65);
            raf.write(65);
            raf.write(65);
//          raf.writeUTF("國科科技");
            
            //先將字串轉成位元組陣列
            raf.write("國科科技".getBytes());
            //獲取指標位置
            System.out.println(raf.getFilePointer());
            //設定指標位置
            raf.seek(3);
            System.out.println(raf.getFilePointer());
            
            //讀資料(當讀到檔案末尾返回-1)
//          System.out.println((char)raf.read());
//          System.out.println((char)raf.read());
//          System.out.println((char)raf.read());
            //可以利用以一次性讀多個位元組讀取中文
//          byte[] bt = new byte[4];
//          System.out.println(raf.read(bt));
//          System.out.println(new String(bt));
            
            byte[] bt = new byte[1024];
            int i= 0;
            while((i=raf.read(bt))!=-1) {
                System.out.println(new String(bt,0,i));
            }
        
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            if (raf != null) {
                try {
                    raf.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
    }
    }
}
​

  

InputStream類(位元組輸入流)

❑ 抽象類 以位元組為基本單元

InputStream方法

FileInputStream

作用:從實際磁碟中讀取檔案的內容,從檔案系統中的某個檔案獲得輸入位元組 (*用於讀取影象資料之類的原始位元組流) ➢ 構造方法 • FileInputStream(File file) • FileInputStream(String name)

OutputStream

FileOutputStream

❑ 把流寫入到檔案。 ❑ 構造方法 FileOutputStream(File file) FileOutputStream(File file, boolean append) FileOutputStream(String name) FileOutputStream(String name, boolean append) append:如果檔案已經存在,append=true表示往檔案追加內容,否則會覆蓋 檔案。 ❑ 舉例:拷貝檔案

public class TestInAndOut {
    public static void main(String[] args) {
        File file = new File("test02.txt");
//      testInputStream(file);
//      testOutputStream(file);
        testCopy();
    }
​
    private static void testCopy() {
        InputStream in = null;
        OutputStream out = null;
        try {
            long start = System.currentTimeMillis();
            in = new FileInputStream("頭飾.png");
            out = new FileOutputStream("copy.png");
            int i = 0;
            byte[] bt = new byte[1024];
            while((i=in.read(bt))!=-1) {
                out.write(bt);
            }
            System.out.println("複製完成....");
            long end = System.currentTimeMillis();
            System.out.println(end-start);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
​
    private static void testInputStream(File file) {
        //輸入流:從檔案讀取到系統記憶體
        InputStream in = null;
        try {
            in = new FileInputStream(file);
//          System.out.println(in.read());
            byte[] bt = new byte[1024];
            int i= 0;
            while((i=in.read(bt))!=-1) {
                System.out.println(new String(bt,0,i));
            }
            
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
    }
​
    private static void testOutputStream(File file) {
        //輸出流:從系統記憶體寫入到檔案
        OutputStream out = null;
        try {
            //append:true表示追加
            out = new FileOutputStream(file,true);
            
            out.write(65);
            out.write(65);
            out.write(65);
            out.write(65);
            out.write(65);
            out.write("國科科技".getBytes());
            System.out.println("寫入完成。。。。");
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
​
}

  

流的套接

❑ 流類可以分為 ❑底層流 包含以位元組的形式讀寫的方法 ❑高層過濾器流 用於讀寫高層資訊 ❑ 高層流要求底層流作為基礎 ❑ 常用高層位元組流: ❑DataInputStream ❑BufferedInputStream ❑ObjectInputStream

高階(過濾)流

❑ FilterInputStream/FilterOutputStream 類的子類包括

• DataInputStream/DataOutputStream ◆ DataInputStream和DataOutputStream提供多種多樣的readxxx和writexxx方法是對多種資料的讀寫。 • BufferedInputStream/BufferedOutputStream ◆ 緩衝位元組輸入/輸出流為InputStream/OutputStream物件增加了緩衝區功能,利用緩衝流可以增 加位元組讀寫的速率,提升應用程式的效能 • PushbackInputStream/PushbackOutputStream

DataInputStream/DataOutputStream

❑ 提供讀取/寫入多種資料的能力 readXXX();writeXXX() ❑ 構造方法 DataInputStream(InputStream in) DataOutputStream(OutputStream out) ❑ DatainputStream/DataOutputStream中文亂碼問題 ❑資料流如果用read/write方法讀寫中文,有可能會出現亂碼問題,解決方法: ❑ String構造方法可以指定對byte陣列做其他編碼方式的解碼,如 new String(bytes,”gbk”);同 時也可以使用readUTF和writeUTF方法解決亂碼問題

public class TestData05 {
    public static void main(String[] args) {
        File file = new File("test01.txt");
//      testWrite(file);
        testRead(file);
    }
​
    private static void testRead(File file) {
        InputStream in = null;
        DataInputStream dis = null;
        try {
            in = new FileInputStream(file);
            dis = new DataInputStream(in);
            System.out.println(dis.readChar());
            System.out.println(dis.readUTF());
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
​
    private static void testWrite(File file) {
        DataOutputStream dos = null;
        OutputStream out = null;
        try {
            //建立位元組輸出流
            out = new FileOutputStream(file);
            //建立高階流,將普通流新增進去
            dos = new DataOutputStream(out);
            dos.writeChar('國');
            dos.writeUTF("龍巖學院");
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
​
}
 

  

BufferedInputStream/BufferedOutputStream

➢ 緩衝輸入/緩衝輸出 ➢ BufferedInputStream支援 mark 和 reset 方法 ➢ 構造方法: • BufferedInputStream(InputStream in) • BufferedInputStream(InputStream in, int size) ➢ 常用方法: • read(bytes[] b,int offset,int length) ◆ 第一個引數:構建緩衝區陣列 ◆ 第二個引數:讀取檔案的起始位置 ◆ 第三個引數:每次讀取檔案的長度 • mark方法和reset方法 ◆ mark(int readlimit):在輸入流的當前位置做標記,配合reset方法的後續呼叫將此流重新定位在最後標記的位置上,以便後續讀取操作重新讀取相同的位元組 ◆ reset():將此流重新定位到對此輸入流最後使用mark方法時的位置

BufferedOutputStream

➢ BufferedOutputStream常用方法: • flush():這是每個輸出流都有的方法,作用為重新整理此輸出流 • write(bytes[] b,int offset,int length): ◆ 第一個引數:構建緩衝區陣列 ◆ 第二個引數:寫入檔案的起始位置 ◆ 第三個引數:每次寫入檔案的長度 • write(int b):將指定位元組b寫入此緩衝的輸出流中

PrintStream

➢ 方便地列印各種資料值表示形式 ➢ 與其他輸出流不同,PrintStream 不會丟擲 IOException;而是,異常情況僅設 置可通過 checkError 方法測試的內部標誌。 ➢ 支援自動重新整理;這意味著可在寫入位元組陣列之後自動呼叫 flush 方法,可呼叫其 中一個 println 方法,或寫入一個新行字元或位元組 (‘\n’)。

public class TestBuffer06 {
    public static void main(String[] args) {
        File file = new File("test01.txt");
//      testWrite(file);
        testRead(file);
    }
​
    private static void testRead(File file) {
        InputStream in = null;
        BufferedInputStream bis = null;
        try {
            in = new FileInputStream(file);
            bis = new BufferedInputStream(in);
            int i = 0;
            byte[] bt = new byte[1024];
            while((i=bis.read(bt))!=-1) {
                System.out.println(new String(bt,0,i));
            }
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
​
    private static void testWrite(File file) {
        OutputStream out = null;
        BufferedOutputStream bos = null;
        try {
            out = new FileOutputStream(file);
            bos = new BufferedOutputStream(out);
            
            bos.write("福建國科資訊科技有限公司".getBytes());
            //重新整理
            bos.flush();
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            try {
                bos.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
​
}
 

  

字元流

配置檔案

❑ 是一個檔案,字尾一般為ini、properties或者xml檔案

❑ 作用:使用者登入時定義載入環境所需的設定和檔案的集合

❑ 格式 鍵=值 ...... ➢ 例如 user=qq password=123456

讀取配置檔案
FileInputStream fis = new FileInputStream(“config.ini”);
Properties prop = new Properties();
//從檔案中載入配置
prop.load(fis);
//根據鍵名取值
String user = prop.getProperty(“user”);
www.goktech.cn
10
修改並儲存配置到檔案
//修改健名為user的健值admin,如果健名不存在,
//則新增。
prop.setProperty("user", "admin");
...
//把prop裡的健值對儲存到檔案config.ini
FileOutputStream fos = new FileOutputStream("config.ini");
prop.store(fos, “備註”);

  


Reader

FileReader

➢ 使讀取字元檔案成為可能

➢ 構造方法 • FileReader(File file) • FileReader(String fileName)

BufferedReader

➢ 從字元輸入流中讀取文字,緩衝各個字元,從而提供單個字元、陣列和字串的 高效寫入。

➢ 構造方法:BufferedReader(Reader r) ➢ readLine() 從流中讀一行

Writer

FileWriter

➢ 允許將字元型別資料寫入檔案

➢ 構造方法 ➢ FileWriter(File file); ➢ FileWriter(String fileName);

BufferedWriter

❑ 將文字寫入字元輸出流,緩衝各個字元,從而提供單個字元、陣列和字串的高 效寫入。 ❑ newLine() ❑ write(String s, int off, int len) ❑ 除非要求提示輸出,否則建議用 BufferedWriter 包裝所有其 write() 操作可 能開銷很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如, PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));

位元組流和字元流轉換

➢ InputStreamReader 把位元組輸入流轉換成字元流

➢ OutputStreamWriter 把字元流寫到位元組流

➢ 例子:用位元組流開啟檔案,然後轉成字元流 FileInputStream fis = new FileInputStream("e:/student.c"); InputStreamReader isr = new InputStreamReader(fis);

獲取鍵盤輸入

//System.in是鍵盤輸入流 //把鍵盤輸入轉成字元流 InputStreamReader isr = new InputStreamReader(System.in); //用緩衝字元流封裝,以允許讀一行 BufferedReader br = new BufferedReader(isr); //從鍵盤讀取一行 String line = br.readLine();

public class test {
​
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File file = new File("text.text");
        
        test01(file);
        test02(file);
    }
​
    private static void test02(File file) {
        // TODO Auto-generated method stub
        OutputStream os= null;
        OutputStreamWriter osw = null;
        BufferedWriter bw = null;
        try {
            os = new FileOutputStream(file);
            osw = new OutputStreamWriter(os,"utf-8");
            osw.write("三好學生");
            
            bw =new BufferedWriter(osw);
            bw.write("全額獎學金");
            bw.flush();
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
​
    private static void test01(File file) {
        //位元組流字元流轉換
        //注意檔案的編碼格式。如果不相同會產生亂碼。可以轉位元組流
        //將位元組的輸入流轉換成字元輸入流
        InputStream in = null;
        InputStreamReader isr = null;
        BufferedReader br =null;
        try {
            in = new FileInputStream(file);
            isr = new InputStreamReader(in,"utf-8");//可以指定讀取的編碼格式
            System.out.println((char)isr.read());//不指定採用系統的編碼格式
            
            //也可以使用緩衝流
            br = new BufferedReader(isr);
            System.out.println(br.readLine());
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
​
}
private static void testSystem() {
        //高階流可以使用
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader reader = new BufferedReader(isr);
        try {
            System.out.println(reader.readLine());
        } catch (Exception e) {
            // TODO: handle exception
        }
        
    }

  

序列化

➢ 序列化是把一個物件的狀態寫入一個位元組流的過程。 ➢ 如果一個物件引用到其它物件,而這些物件又引用另外的物件,那麼所有這些對 象都會被序列化。

Serializable介面

➢ 只有實現Serializable介面的物件才能被序列化工具儲存或者恢復。 ➢ 宣告為transient的變數不被序列化工具儲存。 ➢ static變數同樣不被儲存。

ObjectOutputStream

➢ 構造方法 public ObjectOutputStream(OutputSteam os) ➢ 負責向流寫入物件 public void writeObject(Object obj)

ObjectInputStream

➢ 構造方法 public ObjectInputStream(InputSteam is) ➢ 負責從流讀出物件(反序列化) public Object readObject()

序列化

public class demo02 {
    public static void main(String[] args) {
    People p1 = new People(1,"小明","男",20,"1992-02-18","福建福州");
    People p2 = new People(2,"小紅","女",20,"1992-02-18","福建廈門");
    File file = new File("People.text");
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;
    FileInputStream fis = null;
    ObjectInputStream ois = null;
    
    //序列化
    try {
        fos = new FileOutputStream(file);
        oos = new ObjectOutputStream(fos);
        oos.writeObject(p1);
        oos.writeObject(p2);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }finally {
        try {
            oos.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    //反序列化
    try {
        fis = new FileInputStream(file);
        ois = new ObjectInputStream(fis);
        People p3 = (People)ois.readObject();
        People p4 = (People)ois.readObject();
        System.out.println(p3.toString());
        System.out.println(p4.toString());
    } catch (Exception e) {
        // TODO: handle exception
    }
    }
}
​
public class People implements Serializable{
    private int no;
    private String name;
    private String sex;
    private int age;
    private String date;
    private String address;
    public People(int no, String name, String sex, int age, String date, String address) {
        super();
        this.no = no;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.date = date;
        this.address = address;
    }
    @Override
    public String toString() {
        return "People [no=" + no + ", name=" + name + ", sex=" + sex + ", age=" + age + ", date=" + date + ", address="
                + address + "]";
    }
}