Windows Vista: Cached Reading of a File Opened with No Cache Enabled

本文探讨了在禁用缓存标志的情况下随机读取文件时的缓存行为,包括ReadyBoost缓存命中率提高的现象及其原因分析,还讨论了Superfetch的作用、不同Windows版本间的差异及硬盘内置缓存的影响。
Below are my observation regarding the behavior of randomly reading a file without disk cache.

Question 1: why ReadyBoost cache hit rate raises when reading a file (opened with no cache) randomly?

Answer: from what I observed, it is because ReadyBoost does cache the file, even if it is opened with a flag saying no cache is needed.

Question 2: why the file is opened with no cache enabled, but is still read without much disk activity when it is read the second time?

Answer: from what I observed, it is because not only ReadyBoost, but also RAM is used to cache the file, even if it is opened with a flag saying no cache is needed. One evidence is that at first the ReadyBoost hit read bytes becomes higher during the read, and later I ran it more times the ReadyBoost hit read bytes doesn’t become high any more; instead it is finished quickly without much disk activity.

Question 3: does Superfetch work for files that are opened with no cache enabled?

Answer: I think yes. Otherwise there would be no reason that ReadyBoost can cache the file–ReadyBoost needs Superfetch to populate the data.

Question 4: is Windows Vista different from previous versions of Windows?

Answer: As I compared with Windows 2000 (although running inside VPC, but I can observe the virtual HDD light), Windows 2000 doesn’t do any caching to the file if it is opened with the no cache flag.

Question 5: can it be the hard disk drive built-in cache that caches the data for the process reading a file with the no cache flag?

Answer: no. Because I also tried randomly reading 400MB data, which is signifcantly larger than the HDD built-in cache, but it is still cached. So I think the answer is no.

See also my test programs randreadtest.cs, randreadtest_ca.cs and randreadtest_big.cs.


using System;
using System.IO;
using System.Runtime.InteropServices;
namespace RobbieTests
{
    public class NativeMethods
    {
        [DllImport("Kernel32.dll", SetLastError = true)]
        public static extern IntPtr
            CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile);
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer,
           UInt32 nNumberOfBytesToRead, out UInt32 lpNumberOfBytesRead, IntPtr lpOverlapped);
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool CloseHandle(IntPtr hObject);
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern UInt32 SetFilePointer(
            [In] /*SafeFileHandle*/ IntPtr hFile,
            [In] Int32 lDistanceToMove,
            [In, Out] ref Int32 lpDistanceToMoveHigh,
            [In] UInt32 dwMoveMethod);
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern UInt32 SetFilePointer(
            [In] /*SafeFileHandle*/ IntPtr hFile,
            [In] Int32 lDistanceToMove,
            [In] IntPtr lpDistanceToMoveHigh,
            [In] UInt32 dwMoveMethod);
        public static IntPtr INVALID_HANDLE_VALUE = (IntPtr)(-1);
        public static UInt32 GENERIC_READ = 0×80000000;
        public static UInt32 FILE_SHARE_READ = 0×00000001;
        public static UInt32 FILE_SHARE_WRITE = 0×00000002;
        public static UInt32 OPEN_EXISTING = 0×00000003;
        public static UInt32 FILE_ATTRIBUTE_NORMAL = 0×00000080;
        public static UInt32 FILE_FLAG_NO_BUFFERING = 0×20000000;
        public static UInt32 FILE_BEGIN = 0×00000000;
        public static UInt32 INVALID_SET_FILE_POINTER = 0xFFFFFFFF;
    }
    public class RandReadTest /* random uncached read test */
    {
        public static void Main(string[] args)
        {
            const int BUFSIZE = 4096;
            const int MAXBLOCKCNT = 10240;
            IntPtr hFile = NativeMethods.INVALID_HANDLE_VALUE;
            Random rand = new Random();
            byte[] buffer = new byte[BUFSIZE];
            UInt32 sizeread;
            int i;
            try {
                hFile =
                    NativeMethods.CreateFile(args[0], NativeMethods.GENERIC_READ, NativeMethods.FILE_SHARE_READ | NativeMethods.FILE_SHARE_WRITE,
                    IntPtr.Zero, NativeMethods.OPEN_EXISTING,
                    NativeMethods.FILE_ATTRIBUTE_NORMAL | NativeMethods.FILE_FLAG_NO_BUFFERING, IntPtr.Zero);
                if (hFile == NativeMethods.INVALID_HANDLE_VALUE) {
                    throw new FormatException(“Unable to open the file.”);
                }
                for (i = 0; i < MAXBLOCKCNT; i++) {
                    if (NativeMethods.SetFilePointer(hFile, rand.Next(MAXBLOCKCNT) * BUFSIZE, IntPtr.Zero, NativeMethods.FILE_BEGIN) == NativeMethods.INVALID_SET_FILE_POINTER) {
                        throw new FormatException(“Unable to seek in the file.”);
                    }
                    if (!NativeMethods.ReadFile(hFile, buffer, BUFSIZE, out sizeread, IntPtr.Zero)) {
                        throw new FormatException(“Unable to read the file.”);
                    }
                }
            } catch (Exception ex) {
                Console.WriteLine(ex);
                Console.WriteLine(ex.StackTrace);
            } finally {
                if (hFile != NativeMethods.INVALID_HANDLE_VALUE) {
                    NativeMethods.CloseHandle(hFile);
                }
            }
        }
    }
}



<think>嗯,用户问的是关于文件最后一行缺少换行符的问题以及解决方法。我需要先理解这个问题的背景和原因。记得以前在编程中遇到过类似的警告,比如GCC或其他编译器可能会提示“No newline at end of file”。这可能是因为POSIX标准规定文本文件的行应该以换行符结束,所以不符合这个标准的话,某些工具会报错或者行为异常。 首先,得确认这个问题的具体表现和影响。用户可能在编译代码或者运行脚本时遇到警告或错误,或者版本控制系统如Git在diff时显示最后一行的变化,即使内容没变。这时候需要解释为什么缺少换行符会有问题,比如POSIX的定义,还有不同工具对此的处理方式不同。 然后,解决方案部分。常见的解决办法包括手动在文件末尾添加换行符,或者使用编辑器设置自动添加。比如VS Code、Vim、Sublime Text等都有相关配置。另外,可以介绍用命令行工具如sed或echo来批量处理,这对有多个文件的情况比较有用。对于使用版本控制的用户,可能还需要配置Git的钩子来检查提交的文件是否符合规范。 接下来要考虑用户可能的实际场景。他们可能是在团队协作中遇到这个问题,或者是在自动化构建流程中发现警告。所以需要提供多种解决方法,涵盖不同编辑器和命令行工具,方便用户根据自身情况选择。 另外,用户可能不知道如何检查文件是否缺少换行符,所以需要给出检查的方法,比如使用cat命令或者hexdump查看文件结尾。还有,可能需要解释为什么这个问题重要,比如某些解析器会处理不正确,导致脚本执行错误或者数据读取不完整。 还要注意引用相关的资料,比如POSIX标准,或者某些工具的文档。但根据用户提供的引用内容,似乎没有直接相关的,所以可能需要依赖自己的知识库,或者不引用,但根据系统指令,如果有相关引用的话要加上。不过用户提供的引用可能不相关,所以这里可能不需要引用。 最后,生成相关问题时要考虑用户可能的后续疑问,比如如何批量修复、如何配置Git钩子、不同操作系统的换行符差异,或者这个问题在特定编程语言中的影响。这样能帮助用户更全面地理解和解决问题。</think>### 文件末尾缺少换行符问题解析 #### 问题现象 当文件最后一行的结尾没有换行符(即`\n`)时,POSIX标准会将其视为不完整的文本文件[^1]。具体表现包括: - 编译器(如GCC)提示警告`warning: no newline at end of file` - Git差异对比时显示`\ No newline at end of file` - 部分脚本解析器可能无法正确处理最后一行内容 #### 原因分析 1. **POSIX标准要求**:文本文件的每行必须以换行符结尾,包括最后一行 2. **工具兼容性**:某些工具(如`cat`、`wc`)会依据此标准计算行数 3. **版本控制影响**:Git的diff操作会将该问题标记为文件内容变更 #### 解决方案 **1. 手动修复** - 在文件末尾添加空行(按Enter键) - 使用命令行工具追加换行符: ```bash echo >> filename # 追加空行 sed -i -e '$a\' filename # 兼容性更强的POSIX方法 ``` **2. 编辑器自动修复** - **VS Code**:设置`"files.insertFinalNewline": true` - **Vim**:配置`set fixeol`或执行`:set fileformat=unix` - **Sublime Text**:设置`"ensure_newline_at_eof_on_save": true` **3. 版本控制预处理** 创建Git预提交钩子(`.git/hooks/pre-commit`): ```bash #!/bin/sh # 检查所有待提交文件 git diff --cached --name-only | while read file; do if [ -f "$file" ]; then tail -c1 "$file" | read -r _ || echo >> "$file" fi done ``` **4. IDE批量处理** ```bash # 使用find命令批量修复 find . -type f -name "*.sh" -exec sed -i -e '$a\' {} \; ``` #### 验证方法 ```bash # 检查文件末尾是否包含换行符 cat -e filename | tail -n1 # 使用hexdump查看二进制格式 hexdump -C filename | tail -n2 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值