Java 并发 写文件

Bruthe 2014-06-13 10:34:03
把很多手机客户端发送的数据串接收, 写入到一个文件,可以按天 或者按小时

并发量比较大,传统的 打开文件, 使用文件流写入, 关闭资源 估计不是很可靠把

有什么好的建议的 求大神

import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.SimpleDateFormat;
import java.util.Date;

public class WriterFile {

// 指定大小为 100M 的缓冲区 , 一个存缓存数据,一个把满的缓存写入文件
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("hello test" + i + "\r\n");
else
processtwo("hello test" + i + "\r\n");
}
long end = System.nanoTime();
System.out.println((end - start) + "耗时");
}

/**
* bytebuffertwo写日志
*/
public static void processtwo(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));
//bytebuffer.put(log.getBytes("UTF-8"));
bytebuffer.put(log.getBytes());
//}
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");
//SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd_HH");
String str = format.format(new Date());
return "f:/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();

}
}
}
...全文
642 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
Bruthe 2014-06-16
  • 打赏
  • 举报
回复
引用 5 楼 myhirra 的回复:
1.建立一个tmp文件夹,有一个连接过来,先把这个连接的内容存到1.tmp里面,依次,再来一个存到2.tmp。每一个小时统计这个文件夹内容,将所有数据写到你指定的文件中去。可解决问题,但是磁盘io开销较大。 2.开辟一个缓冲内存(队列的形式),足够大,有一个连接就往里面写。每个小时写完后清空。
恩 是的
Bruthe 2014-06-16
  • 打赏
  • 举报
回复
引用 7 楼 hanpoyangtitan 的回复:
之前写过手机手机客户端信息的程序直接用了log4j写到日志文件里,并发量大看你服务器架构如何了,如果单台服务器,你的服务能撑住是没问题的,集群的话各写各的,也没问题。
哈哈 , 仁兄 虽然log4j是个记录日志的, 但是用到我这个单独的,只接受数据功能的上也没问题,有点取巧.自己写的程序稳定性还没log4j高,也对 ,我对这个类单独配个输出文件,这样也也解决问题了, 在jmeter上测试了 ,单台服务器 每秒2000-3000的并发 没有问题
Bruthe 2014-06-16
  • 打赏
  • 举报
回复

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.iresearch.appstore.util.WriterFileUtil;

/**
 * Servlet implementation class WriteServlet
 */
public class WriteServlet extends HttpServlet {
	
	protected final Logger logger = Logger.getLogger(this.getClass());
	
	private final static long serialVersionUID = 1L;
	private volatile boolean isRunning = false; 
	
	AtomicInteger  count  = new AtomicInteger();
	DateFormat format = new SimpleDateFormat("yyyyMMdd_HH");
	BlockingQueue<String> queue = new LinkedBlockingQueue<String>(100000);  
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public WriteServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		logger.info( request.getParameter("jsonstr") + count.incrementAndGet()+ "\r\n" );
		/*if(queue.offer(request.getParameter("jsonstr") + count.incrementAndGet()+ "\r\n")){
			//System.out.println("put data to queue sucess..");
		}else{
			System.out.println("put data to queue failed..");
		}
		
		if(!isRunning){  
			Thread writeFile = new Thread(new WriteFile());  
			writeFile.start();        
        }  */
	}
	
	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
	
	class WriteFile implements Runnable {
		@Override
		public void run() {
			isRunning = true;
			try {
				while (isRunning) {
					/*
					 * 2秒内取不到就返回null,也可以用take方法,取不到数据会阻塞,isRunning可以不用
					 */
					
					/*String data = queue.poll(2, TimeUnit.SECONDS);
					if (null != data) {
						System.out.println("正在处理第" + data + "次请求!");
						Thread.sleep(5000);
					} else {
						System.out.println("队列里没数据!");
						// 超过2s还没数据,自动退出线程。
						isRunning = false;
					}*/
					
					//get data from queue up to 10000
					List<String> jsonList = new ArrayList<String>();
					Integer jsonNum = queue.drainTo(jsonList, 1000);
					//Integer jsonNum = queue.drainTo(jsonList);
					System.out.println("获取:" + jsonNum + " 条数据");
					if(null!=jsonNum && jsonNum>0){
						WriterFileUtil.write(jsonList, format.format(new Date()));
						System.out.println("写入文件成功..");
						Thread.sleep(5 * 1000);
					} else {
						System.out.println("队列里没数据!");
						// 超过2s还没数据,自动退出线程。
						isRunning = false;
					}
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}
写文件类

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List;

public class WriterFileUtil {
	
	private final static String DIR_NAME = "f:/test/";
	private final static String FILE_SUFFIX = ".txt";
	
	private static FileOutputStream fos = null;
	private static FileChannel fc =null;
	private static ByteBuffer bf = null;
	
	public static void write(List<String>jsonList, String timestr) {
		
		StringBuffer buffer = new StringBuffer();
		for(String jsonstr : jsonList){
			buffer.append(jsonstr);
		}
		
		try {
			fos = new FileOutputStream(DIR_NAME + timestr + FILE_SUFFIX, true);
			
 			fc = fos.getChannel();
			bf = ByteBuffer.allocate(1024*10000);
			bf.put( (buffer.toString()).getBytes() );

			/*System.out.println((buffer.toString()).getBytes().length);
			System.out.println(bf.position());
			System.out.println(bf.limit());*/
			
			bf.flip();
			fc.write(bf);
            fc.close(); 
            fos.close();

		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
什么都不能 2014-06-14
  • 打赏
  • 举报
回复
之前写过手机手机客户端信息的程序直接用了log4j写到日志文件里,并发量大看你服务器架构如何了,如果单台服务器,你的服务能撑住是没问题的,集群的话各写各的,也没问题。
myhirra 2014-06-13
  • 打赏
  • 举报
回复
1.建立一个tmp文件夹,有一个连接过来,先把这个连接的内容存到1.tmp里面,依次,再来一个存到2.tmp。每一个小时统计这个文件夹内容,将所有数据写到你指定的文件中去。可解决问题,但是磁盘io开销较大。 2.开辟一个缓冲内存(队列的形式),足够大,有一个连接就往里面写。每个小时写完后清空。
jmppok 2014-06-13
  • 打赏
  • 举报
回复
缓冲吧,先写进一个内存队列,定期将内存队列中的数据写入文件。
lsongiu86 2014-06-13
  • 打赏
  • 举报
回复
不难解决,写一个单独的线程往文件中写入内容,把接收到的内容放在内存中,最好是放在一个全局的blockingqueue中,写文件的线程在该blockingqueue中获取数据,依次写入,并发量不是超级大或者写入内容如果不是超级大的话,这个方法应该没问题,而且blockingqueue 线程安全
Bruthe 2014-06-13
  • 打赏
  • 举报
回复
求大神提意见 谢谢啊
Bruthe 2014-06-13
  • 打赏
  • 举报
回复
这是本地的测试程序, 那如果转为web程序, 这个boolean checkbuffer = true, 在并发量比较大的情况下会出现安全问题吧
teemai 2014-06-13
  • 打赏
  • 举报
回复
Java中处理文件就那么多的API。 使用缓冲流,临时文件等等来提高写的性能

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧