電商系統需要記錄用戶行為,需要一個高并發高速寫入文件,考慮利用緩存和noi機制寫入數據,具體邏輯是2塊緩存區,一塊寫數據,一塊寫文件,交替進行,并且利用noi機制一次寫入數據。
測試結果: 1億條數據用時93秒,生產58個100m文件。每一條953納秒。
測試結果: 1億條數據用時93秒,生產58個100m文件。每一條953納秒。
package io.netty.example.http.snoop;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class WriterFile {
// 指定大小為 1024 的緩沖區
public static ByteBuffer bytebufferone = ByteBuffer.allocate(102400000);
public static ByteBuffer bytebuffertwo = ByteBuffer.allocate(102400000);
public static boolean checkbuffer =true;
public static void main(String[] args) {
long start = System.nanoTime();
for(int i=0;i<100000000;i++){
if(checkbuffer)
processone("123abc"+i+"\r\n");
else
prcesstwo("123abc"+i+"\r\n");
}
long end = System.nanoTime();
System.out.println((end - start)+"耗時");
}
/**
* bytebuffertwo寫日志
*/
public static void prcesstwo(String log)
{
//寫bytebuff
boolean onecheck=checkposition(log,bytebuffertwo);
if(onecheck)
writerbuffer(log,bytebuffertwo);
//寫文件
else{
checkbuffer=true;
writerbuffer(log,bytebufferone);
writerfile(bytebuffertwo);
}
}
/**
* bytebufferone寫日志
* @param log
*/
public static void processone(String log)
{
//寫bytebuff
boolean onecheck=checkposition(log,bytebufferone);
if(onecheck){
writerbuffer(log,bytebufferone);
}
//寫文件
else{
checkbuffer=false;
writerbuffer(log,bytebuffertwo);
writerfile(bytebufferone);
}
}
/**
* 判斷緩存是否可以寫下日志
* @param log
* @return
*/
public static boolean checkposition(String log,ByteBuffer bytebuffer)
{
if(2*log.getBytes().length>bytebuffer.limit()-bytebuffer.position())
{
return false;
}
else
{
return true;
}
}
/**
* 寫日志到緩存,并且返回緩存指針位置
* @param log
* @return
*/
public static int writerbuffer(String log,ByteBuffer bytebuffer )
{
for (int i = 0; i < log.length(); i++) {
bytebuffer.putChar(log.charAt(i));
}
return bytebuffer.position();
}
/**
* 寫文件
* @param filename
*/
public static void writerfile(ByteBuffer bytebuffer)
{
try{
FileOutputStream fos = new FileOutputStream(Datefile());
FileChannel fc = fos.getChannel();
bytebuffer.flip();
fc.write(bytebufferone);
fc.close();
fos.close();
bytebuffer.clear();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
/**
* 文件名按日期生產
* @param str
* @return
*/
public static String Datefile() {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
String str = format.format(new Date());
return "d:/test/"+str+".txt";
}
}
附帶一個普通的nio讀寫
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class WriterFile {
// 指定大小為 1024 的緩沖區
public static ByteBuffer bytebufferone = ByteBuffer.allocate(102400000);
public static ByteBuffer bytebuffertwo = ByteBuffer.allocate(102400000);
public static boolean checkbuffer =true;
public static void main(String[] args) {
long start = System.nanoTime();
for(int i=0;i<100000000;i++){
if(checkbuffer)
processone("123abc"+i+"\r\n");
else
prcesstwo("123abc"+i+"\r\n");
}
long end = System.nanoTime();
System.out.println((end - start)+"耗時");
}
/**
* bytebuffertwo寫日志
*/
public static void prcesstwo(String log)
{
//寫bytebuff
boolean onecheck=checkposition(log,bytebuffertwo);
if(onecheck)
writerbuffer(log,bytebuffertwo);
//寫文件
else{
checkbuffer=true;
writerbuffer(log,bytebufferone);
writerfile(bytebuffertwo);
}
}
/**
* bytebufferone寫日志
* @param log
*/
public static void processone(String log)
{
//寫bytebuff
boolean onecheck=checkposition(log,bytebufferone);
if(onecheck){
writerbuffer(log,bytebufferone);
}
//寫文件
else{
checkbuffer=false;
writerbuffer(log,bytebuffertwo);
writerfile(bytebufferone);
}
}
/**
* 判斷緩存是否可以寫下日志
* @param log
* @return
*/
public static boolean checkposition(String log,ByteBuffer bytebuffer)
{
if(2*log.getBytes().length>bytebuffer.limit()-bytebuffer.position())
{
return false;
}
else
{
return true;
}
}
/**
* 寫日志到緩存,并且返回緩存指針位置
* @param log
* @return
*/
public static int writerbuffer(String log,ByteBuffer bytebuffer )
{
for (int i = 0; i < log.length(); i++) {
bytebuffer.putChar(log.charAt(i));
}
return bytebuffer.position();
}
/**
* 寫文件
* @param filename
*/
public static void writerfile(ByteBuffer bytebuffer)
{
try{
FileOutputStream fos = new FileOutputStream(Datefile());
FileChannel fc = fos.getChannel();
bytebuffer.flip();
fc.write(bytebufferone);
fc.close();
fos.close();
bytebuffer.clear();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
/**
* 文件名按日期生產
* @param str
* @return
*/
public static String Datefile() {
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HHmmss");
String str = format.format(new Date());
return "d:/test/"+str+".txt";
}
}
附帶一個普通的nio讀寫
public static void test()
{
try{
FileOutputStream fos = new FileOutputStream("d:/nio.txt");
// 得到文件通道
FileChannel fc = fos.getChannel();
// 指定大小為 1024 的緩沖區
ByteBuffer bf = ByteBuffer.allocate(1024);
// 要寫入文件的字符串
String greeting = "Hello111";
// 把以上字符串逐字放入緩沖區
for (int i = 0; i < greeting.length(); i++) {
bf.putChar(greeting.charAt(i));
}
// 記得執行這個方法,使得 position=0, limit=30, 才能寫入正確的數據
// 否則 position 為 30, limit 為 1024,將會把 30 之后的全部空數據(0) 填到文件中
System.out.println(greeting.getBytes().length);
System.out.println(bf.position());
System.out.println(bf.limit());
bf.flip();
// 緩沖區數據寫入到文件中,會把緩沖區中從 position 到 limit 之間的數據寫入文件
fc.write(bf);
fc.close(); // 關閉文件通道
fos.close(); // 關閉文件輸出流
}catch(Exception e){
e.printStackTrace();
}
}
{
try{
FileOutputStream fos = new FileOutputStream("d:/nio.txt");
// 得到文件通道
FileChannel fc = fos.getChannel();
// 指定大小為 1024 的緩沖區
ByteBuffer bf = ByteBuffer.allocate(1024);
// 要寫入文件的字符串
String greeting = "Hello111";
// 把以上字符串逐字放入緩沖區
for (int i = 0; i < greeting.length(); i++) {
bf.putChar(greeting.charAt(i));
}
// 記得執行這個方法,使得 position=0, limit=30, 才能寫入正確的數據
// 否則 position 為 30, limit 為 1024,將會把 30 之后的全部空數據(0) 填到文件中
System.out.println(greeting.getBytes().length);
System.out.println(bf.position());
System.out.println(bf.limit());
bf.flip();
// 緩沖區數據寫入到文件中,會把緩沖區中從 position 到 limit 之間的數據寫入文件
fc.write(bf);
fc.close(); // 關閉文件通道
fos.close(); // 關閉文件輸出流
}catch(Exception e){
e.printStackTrace();
}
}