异步读写文件的问题,是我写的代码有问题,还是出大事了?彻底蒙了。
发布于 5 年前 作者 jyk0011 3997 次浏览 来自 问答

要求:web服务,记录每次访问记录,保存到文本文件。 测试目的:异步读写文件是否安全,多人访问下是否可以完整记录。

代码,先写个最简单的代码进行测试。把每次访问的url记录下来。

测试方法,在一个网页里使用多个iframe,模拟多人同时访问。

var fs = require(‘fs’); var http = require(“http”); http.createServer(function (request, response) { response.writeHeader(200, { “Content-Type”: “text/html” }); response.write(“Hello World编码!<br>\n”); response.write("<br> url:"+request.url);

if (request.url != '/favicon.ico'){
    fs.readFile('./json.txt', 'utf8', function(err, data){
        console.log(data);
        fs.writeFile('./json.txt',data +'\r\n'+ request.url ,function(err){
            if(err) console.log('写文件操作失败');
            else console.log('写文件操作成功 ' + request.url);
        });
    });
}
 response.end();

}).listen(8080);

网页访问

<html lang=“en”> <head> <meta charset=“UTF-8”> <title>Title</title> </head> <body> <iframe src=“http://127.0.0.1:8080/1”></iframe> <iframe src=“http://127.0.0.1:8080/22”></iframe> <iframe src=“http://127.0.0.1:8080/333”></iframe> <iframe src=“http://127.0.0.1:8080/4444”></iframe> <iframe src=“http://127.0.0.1:8080/55555”></iframe> <iframe src=“http://127.0.0.1:8080/666666”></iframe> <iframe src=“http://127.0.0.1:8080/7777777”></iframe> <iframe src=“http://127.0.0.1:8080/88888888”></iframe> <iframe src=“http://127.0.0.1:8080/999999999”></iframe> <iframe src=“http://127.0.0.1:8080/aaaaaaaaaa”></iframe> <iframe src=“http://127.0.0.1:8080/bbbbbbbbbbb”></iframe> <iframe src=“http://127.0.0.1:8080/cccccccccccc”></iframe> <iframe src=“http://127.0.0.1:8080/ddddddddddddd”></iframe> <iframe src=“http://127.0.0.1:8080/eeeeeeeeeeeeee”></iframe> <iframe src=“http://127.0.0.1:8080/fffffffffffffff”></iframe> <iframe src=“http://127.0.0.1:8080/gggggggggggggggg”></iframe> <iframe src=“http://127.0.0.1:8080/hhhhhhhhhhhhhhhhhh”></iframe>

</body> </html>

首先问问这种写法有没有什么致命问题,如果有的话,怎么改代码。

这个代码有个小问题,没有事先判断文件是否存在,但是这个不是大事。

测试方法,打开那个有很多iframe的网页,模拟多次访问,然后看看日志文件,然后刷新页面,再次看内容,重复多次。

理想情况下,每次访问都会先读取文件内容,然后把url加在最后,在重新保存文件,这样每次访问都会被记录下来,不会有漏掉的。

但是实际测试的时候却发现,不仅有漏掉的访问记录,而且还会把上一轮的内容覆盖掉。 但是并不是每次都会把以前的记录覆盖掉。 完全没发现任何规律。

刷新两次网页后,日志文件是这个样子的

/cccccccccccc /ddddddddddddd /eeeeeeeeeeeeee /fffffffffffffff /gggggggggggggggg /hhhhhhhhhhhhhhhhhh /1 /333 /55555 /7777777 /88888888 /999999999 /aaaaaaaaaa /bbbbbbbbbbb /cccccccccccc /ddddddddddddd /eeeeeeeeeeeeee /fffffffffffffff /gggggggggggggggg /hhhhhhhhhhhhhhhhhh

再刷新网页,又变成这个样子

/666666 /aaaaaaaaaa /bbbbbbbbbbb /ddddddddddddd /eeeeeeeeeeeeee /fffffffffffffffg /hhhhhhhhhhhhhhhhhh /1 /333 /4444 /55555 /666666 /7777777 /88888888 /aaaaaaaaaa /bbbbbbbbbbb /cccccccccccc /ddddddddddddd /fffffffffffffff /hhhhhhhhhhhhhhhhhh

再刷新,简单了,就剩下六行了。

/cccccccccccc /ddddddddddddd /eeeeeeeeeeeeee /fffffffffffffff /gggggggggggggggg /hhhhhhhhhhhhhhhhhh

每次刷新网页后,日志文件的内容都不完整,而且没发现啥规律。

12 回复

写入可以直接用追加模式。先读再写,这肯定是不对的。

@myy 那么代码具体怎么写呀。

@myy 找到追加的方式了,追加的方式没有问题了。想了一下,我这么读和写是分开的,中间会释放CPU,导致打开后没等写入呢,另一个读操作就被执行了,但是记录丢失。 但是还有一个疑问,用一开始的方法,当第一次刷新后,文件里面已经有记录了。 然后再次刷新网页,新的访问记录会丢失,可以理解了,但是上次已经保存好的记录,为啥也丢失了呢?

官网上面有这句话: image.png

@BigKongfuPanda 是不是可以理解为线程不安全?

@jyk0011 node没有多线程说法,应该没有什么安不安全的说法,只是因为顺序问题,你用readfile和writeFile对同一个文件操作,又不用await进行等待,注意,writeFile的说明:Asynchronously writes data to a file, replacing the file if it already exists.不等待回调,肯定会有先后问题,直接导致有时候一个请求1到了,你把txt读到的数据放在内存是状态A,在写的过程中,另一个请求2又到了,又读一次txt,状态也是A,结果请求1写的文件是状态A追加的一个请求1的URL,而接下来请求2写的也是状态A追加的一个请求2的URL,到这里,你的txt在文件里面就不会有请求1的URL了

@HobaiRiku fs模块是使用了多线程的

@zy445566 多线程是怎么样的?

@HobaiRiku 以前就是线程池从uv_work队列里面拿请求执行IO,之前有人喊过用 Linux2.6原生AIO,但因为win平台的原因没做成。

@zy445566 这个是fs模块实现的内容吧?我觉得和node没什么直接关系呀,node也有线程池?哪个模块?

@HobaiRiku 你是和我开玩笑么?fs不属于node?

@zy445566 我的意思是,node如何操作线程?

回到顶部