順序IO和随機IO
對于磁盤的讀寫分為兩種模式,順序IO和随機IO。 随機IO存在一個尋址的過程,是以效率比較低。而順序IO,相當于有一個實體索引,在讀取的時候不需要尋找位址,效率很高。
網上盜了一個圖(侵權删)
Java中的随機讀寫
在Java中讀寫檔案的方式有很多種,先總結以下3種方法:
FileWriter和FileReader
public static void fileWrite(String filePath, String content) {
File file = new File(filePath);
//建立FileWriter對象
FileWriter writer = null;
try {
//如果檔案不存在,建立檔案
if (!file.exists())
file.createNewFile();
writer = new FileWriter(file);
writer.write(content);//寫入内容
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void fileRead(String filePath) {
File file = new File(filePath);
if (file.exists()) {
try {
//建立FileReader對象,讀取檔案中的内容
FileReader reader = new FileReader(file);
char[] ch = new char[1];
while (reader.read(ch) != -1) {
System.out.print(ch);
}
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
BufferedReader和BufferedWriter BufferedReader和BufferedWriter與 FileWriter和FileReader
代碼的寫法一緻,Buffer也多了一個讀取一行字元的操作。
FileWriter和FileReader
public class BuffredRWHelper {
public static void fileWrite(String filePath, String content) {
File file = new File(filePath);
//建立FileWriter對象
BufferedWriter writer = null;
try {
//如果檔案不存在,建立檔案
if (!file.exists())
file.createNewFile();
writer = new BufferedWriter(new FileWriter(file));
writer.write(content);//寫入内容
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void fileRead(String filePath) {
File file = new File(filePath);
if (file.exists()) {
try {
//建立FileReader對象,讀取檔案中的内容
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
System.out.print(line);
}
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
FileInputStream和FileOutputStream 使用Stream的形式是最原始的方式,以位元組數組為中間的中轉緩解
public static void fileWrite(String filePath, String content) {
FileOutputStream outputStream = null;
try {
File file = new File(filePath);
boolean isCreate = file.createNewFile();//建立檔案
if (isCreate) {
outputStream = new FileOutputStream(file);//形參裡面可追加true參數,表示在原有檔案末尾追加資訊
outputStream.write(content.getBytes());
}else {
outputStream = new FileOutputStream(file,true);//表示在原有檔案末尾追加資訊
outputStream.write(content.getBytes());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void fileRead(String filePath) {
File file = new File(filePath);
if (file.exists()) {
try {
//建立FileInputStream對象,讀取檔案内容
FileInputStream fis = new FileInputStream(file);
byte[] bys = new byte[1024];
while (fis.read(bys, 0, bys.length) != -1) {
//将位元組數組轉換為字元串
System.out.print(new String(bys, StandardCharsets.UTF_8));
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Java中的順序讀寫
上面的對檔案的讀寫都是随機讀寫,如果用來寫比較小的日志檔案還能滿足要求,如果用來操作一個檔案的讀寫,那可能帶來很大的性能消耗。
順序IO的讀寫在中間件使用的很頻繁,尤其是在隊列中。幾乎所有的隊列(kafka,qmq等使用檔案存儲消息)都采用了順序IO讀寫。
與随機讀寫不同的是,順序讀寫是優先配置設定一塊檔案空間,然後後續内容追加到對應空間内。
在使用順序IO進行檔案讀寫時候,需要知道上次寫入的地方,是以需要維護一個索引或者輪詢獲得一個沒有寫入位置。
public static long fileWrite(String filePath, String content, int index) {
File file = new File(filePath);
RandomAccessFile randomAccessTargetFile;
MappedByteBuffer map;
try {
randomAccessTargetFile = new RandomAccessFile(file, "rw");
FileChannel targetFileChannel = randomAccessTargetFile.getChannel();
map = targetFileChannel.map(FileChannel.MapMode.READ_WRITE, 0, (long) 1024 * 1024 * 1024);
map.position(index);
map.put(content.getBytes());
return map.position();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return 0L;
}
public static String fileRead(String filePath, long index) {
File file = new File(filePath);
RandomAccessFile randomAccessTargetFile;
MappedByteBuffer map;
try {
randomAccessTargetFile = new RandomAccessFile(file, "rw");
FileChannel targetFileChannel = randomAccessTargetFile.getChannel();
map = targetFileChannel.map(FileChannel.MapMode.READ_WRITE, 0, index);
byte[] byteArr = new byte[10 * 1024];
map.get(byteArr, 0, (int) index);
return new String(byteArr);
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return "";
}
檔案合并方法:
/**
* 檔案合并
*/
public static void mergeFile(List<String> inputPaths, String outputPath) throws FileNotFoundException {
Vector<InputStream> inputStream = new Vector<InputStream>();
if (CollectionUtils.isEmpty(inputPaths)) {
throw new LogicException("合并檔案路徑不能為空");
}
for (String inputPath : inputPaths) {
InputStream in = new FileInputStream(new File(inputPath));
inputStream.add(in);
}
//構造一個合并流
SequenceInputStream stream = new SequenceInputStream(inputStream.elements());
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(
new FileOutputStream(outputPath));
byte[] bytes = new byte[10240];
int len = -1;
while((len=stream.read(bytes))!=-1){
bos.write(bytes,0,len);
bos.flush();
}
log.info("檔案合并完成!");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (null != bos ) {
bos.close();
}
stream.close();
} catch (IOException ignored) {
}
}
}