You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js文件夹文件展示应用问题:文件变更无法同步至页面

Fixing Real-Time Folder Updates in Your Node.js File List API

Hey there! Let's tackle that real-time file update issue you're facing with your Node.js API. The core problem with your current code is that it only reads the folder structure once when the server starts (via that setTimeout call), and never refreshes the data afterward. That's why any new files or deletions don't show up in your HTML page. Let's fix this with two solid approaches, depending on your needs.

Why Your Current Code Isn't Updating

Let's quickly break down the key issues:

  • You populate the items array once at startup, but never re-read the folders when changes happen.
  • The callback-based fs functions and setTimeout create unreliable timing—you can't guarantee the folder read finishes before the first API request.
  • No error handling for cases like missing folders or read permissions.
  • Using for...in to iterate over arrays can cause unexpected behavior (it iterates over object properties, not just array elements).

Approach 1: Re-read Folders on Every API Request

This is the simplest fix—every time your frontend calls /FileCount, we fresh-read the entire folder structure. This ensures you always get the latest state, with minimal code changes.

We'll use fs.promises and async/await to clean up the callback mess and make the code more reliable:

const fs = require('fs').promises;
const express = require('express');
const cors = require('cors');
const path = require('path'); // For cross-platform path handling

const app = express();
app.use(cors());
app.use(express.static(__dirname));

const baseDir = 'Invoices';

// Async function to read the full folder structure
async function getUpdatedFolderStructure() {
  const folderItems = [];
  
  try {
    // Read the main Invoices directory
    const mainDirFiles = await fs.readdir(baseDir);
    
    for (const subFolderName of mainDirFiles) {
      const subFolderPath = path.join(baseDir, subFolderName);
      const stats = await fs.stat(subFolderPath);
      
      // Only process subdirectories (error, processed, unprocessed)
      if (stats.isDirectory()) {
        // Read files inside the subfolder
        const subFolderFiles = await fs.readdir(subFolderPath);
        
        // Map files to your desired format
        const fileRecords = subFolderFiles.map(file => ({
          filename: file,
          filepath: path.join(subFolderPath, file)
        }));
        
        folderItems.push({
          file: subFolderName,
          count: subFolderFiles.length,
          files: fileRecords
        });
      }
    }
    
    return folderItems;
  } catch (err) {
    console.error('Failed to read folder structure:', err);
    throw err; // Let Express handle the error response
  }
}

// Update the API endpoint to fetch fresh data on every request
app.get('/FileCount', async (req, res) => {
  try {
    const latestFolderData = await getUpdatedFolderStructure();
    res.send(latestFolderData);
  } catch (err) {
    res.status(500).send({ error: 'Unable to retrieve folder data' });
  }
});

app.listen(4000, () => {
  console.log('Listening on port 4000');
});

Pros of This Approach:

  • Dead simple to implement—no extra listening logic needed.
  • Guaranteed fresh data on every request.
  • Cleaner, more maintainable code with async/await and proper error handling.
  • Uses path.join to avoid cross-platform path issues (e.g., / vs \ on Windows).

Best For:

Low-traffic scenarios where you don't mind the small overhead of re-reading folders on each request.


Approach 2: Watch for Folder Changes (Cached Data)

If your frontend makes frequent requests to /FileCount, re-reading folders every time can waste resources. Instead, we'll use Node's built-in fs.watch to monitor the folders for changes, and keep a cached copy of the folder structure that updates automatically.

const fs = require('fs').promises;
const fsSync = require('fs');
const express = require('express');
const cors = require('cors');
const path = require('path');

const app = express();
app.use(cors());
app.use(express.static(__dirname));

const baseDir = 'Invoices';
let cachedFolderData = []; // Cache to store the latest folder structure

// Function to refresh the cached folder data
async function refreshCachedData() {
  try {
    const folderItems = [];
    const mainDirFiles = await fs.readdir(baseDir);
    
    for (const subFolderName of mainDirFiles) {
      const subFolderPath = path.join(baseDir, subFolderName);
      const stats = await fs.stat(subFolderPath);
      
      if (stats.isDirectory()) {
        const subFolderFiles = await fs.readdir(subFolderPath);
        const fileRecords = subFolderFiles.map(file => ({
          filename: file,
          filepath: path.join(subFolderPath, file)
        }));
        
        folderItems.push({
          file: subFolderName,
          count: subFolderFiles.length,
          files: fileRecords
        });
      }
    }
    
    cachedFolderData = folderItems;
    console.log('Folder data refreshed');
  } catch (err) {
    console.error('Failed to refresh folder data:', err);
  }
}

// Set up watchers for the main folder and its subfolders
function setupFolderWatchers() {
  // Watch the main Invoices directory for new/removed subfolders
  fsSync.watch(baseDir, (eventType, filename) => {
    if (filename) {
      console.log(`Change detected in ${baseDir}: ${filename}`);
      refreshCachedData();
    }
  });

  // Watch each subfolder for file changes
  async function watchSubFolders() {
    const mainDirFiles = await fs.readdir(baseDir);
    for (const subFolderName of mainDirFiles) {
      const subFolderPath = path.join(baseDir, subFolderName);
      const stats = await fs.stat(subFolderPath);
      
      if (stats.isDirectory()) {
        fsSync.watch(subFolderPath, (eventType, file) => {
          console.log(`Change detected in ${subFolderPath}: ${file}`);
          refreshCachedData();
        });
      }
    }
  }
  
  watchSubFolders();
}

// Initialize cached data and start server
(async () => {
  await refreshCachedData();
  setupFolderWatchers();
  
  app.listen(4000, () => {
    console.log('Listening on port 4000');
  });
})();

// API endpoint returns cached data
app.get('/FileCount', (req, res) => {
  res.send(cachedFolderData);
});

Pros of This Approach:

  • Faster API responses since we return cached data instead of re-reading folders every time.
  • Automatic updates whenever files or folders are added/removed.

Notes:

  • fs.watch behavior can vary slightly across operating systems (e.g., multiple events for a single change). For more reliable cross-platform watching, you could use a library like chokidar (but that's an extra dependency).
  • We initialize the cache on server startup so the first request has valid data.

Best For:

High-traffic scenarios where you want to minimize disk I/O and keep API responses fast.


Final Tips for Your Frontend

To make the updates feel truly real-time, your HTML page can:

  • Poll the /FileCount endpoint at regular intervals (e.g., every 2-5 seconds) using setInterval.
  • Or use WebSockets to push updates from the server to the frontend when changes are detected (but that's an extra layer of complexity).

内容的提问来源于stack exchange,提问作者Arti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:08:40