How to Upload and Read File Contents in React: Fixing the C:fakepath Issue

File uploads are a common requirement in modern web applications—whether you’re building a document management system, a social media platform for image sharing, or a tool that processes user-uploaded text files. React, being a popular frontend library, provides straightforward ways to handle file uploads, but developers often encounter a quirky issue: when trying to display the path of an uploaded file, the browser shows C:fakepath\filename.ext instead of the actual file path.

This "fakepath" problem is not a bug but a security feature implemented by browsers to protect users’ file system privacy. In this blog, we’ll walk through how to set up file uploads in React, read file contents (text, images, etc.), and most importantly, fix the C:fakepath issue for a seamless user experience.

Table of Contents#

Prerequisites#

Before diving in, ensure you have:

  • Basic knowledge of React (functional components, hooks like useState).
  • Node.js and npm/yarn installed.
  • A React project set up (e.g., using create-react-app or Vite).

Basic File Upload in React#

Let’s start with the fundamentals: creating a file input to let users select files from their system.

Step 1: Create a File Input Component#

In React, a file input is created using <input type="file" />. This element renders a button that opens the system’s file picker when clicked. We’ll use React’s useState hook to track the selected file.

import React, { useState } from 'react';
 
const FileUploader = () => {
  const [selectedFile, setSelectedFile] = useState(null);
 
  // Handle file selection
  const handleFileSelect = (event) => {
    // Get the first selected file (single file upload)
    const file = event.target.files[0];
    if (file) {
      setSelectedFile(file);
      console.log('Selected file:', file);
    }
  };
 
  return (
    <div className="file-uploader">
      <h3>Basic File Upload</h3>
      {/* File input element */}
      <input
        type="file"
        onChange={handleFileSelect}
        style={{ display: 'none' }} // Hide default input (optional)
        id="file-input"
      />
      {/* Custom button to trigger file picker */}
      <label htmlFor="file-input" className="btn">
        Select File
      </label>
      {/* Display selected file name */}
      {selectedFile && (
        <p className="file-name">Selected: {selectedFile.name}</p>
      )}
    </div>
  );
};
 
export default FileUploader;

Key Notes:#

  • The <input type="file" /> element’s onChange event triggers when a file is selected. The selected files are stored in event.target.files (a FileList object, similar to an array).
  • We hide the default input (with display: none) and use a <label> to trigger it, allowing for custom styling of the "Select File" button.
  • selectedFile is stored in state, and we display selectedFile.name to show the user which file was chosen.

Reading File Contents with the FileReader API#

Once a file is selected, you’ll often need to read its content (e.g., display text from a .txt file or preview an image). This is where the browser’s FileReader API comes in.

What is FileReader?#

FileReader is a built-in browser API that lets you asynchronously read the contents of files (or blobs) stored on the user’s device. It supports multiple reading methods:

  • readAsText(file): Reads the file as plain text.
  • readAsDataURL(file): Reads the file as a base64-encoded string (useful for images).
  • readAsArrayBuffer(file): Reads the file as raw binary data (for advanced use cases like file processing).

Example 1: Read Text Files#

Let’s extend the previous component to read and display the content of text files (e.g., .txt, .csv):

import React, { useState } from 'react';
 
const TextFileReader = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  const [fileContent, setFileContent] = useState('');
 
  const handleFileSelect = (event) => {
    const file = event.target.files[0];
    if (file) {
      setSelectedFile(file);
      readFileContent(file); // Read content after selection
    }
  };
 
  // Read file content using FileReader
  const readFileContent = (file) => {
    const reader = new FileReader();
 
    // Handle successful read
    reader.onload = (event) => {
      const content = event.target.result;
      setFileContent(content);
    };
 
    // Handle errors
    reader.onerror = () => {
      console.error('Error reading file:', reader.error);
    };
 
    // Read the file as text
    reader.readAsText(file);
  };
 
  return (
    <div className="text-file-reader">
      <h3>Read Text File Content</h3>
      <input
        type="file"
        onChange={handleFileSelect}
        accept=".txt,.csv,.md" // Restrict to text-based files
        id="text-file-input"
      />
      <label htmlFor="text-file-input" className="btn">
        Select Text File
      </label>
 
      {selectedFile && (
        <div className="file-info">
          <p>File: {selectedFile.name}</p>
          <p>Size: {Math.round(selectedFile.size / 1024)} KB</p>
        </div>
      )}
 
      {/* Display file content */}
      {fileContent && (
        <div className="file-content">
          <h4>Content:</h4>
          <pre>{fileContent}</pre> {/* Pre tag preserves whitespace */}
        </div>
      )}
    </div>
  );
};
 
export default TextFileReader;

Example 2: Preview Images#

To read and display image files (e.g., .jpg, .png), use readAsDataURL to convert the image to a base64 string:

import React, { useState } from 'react';
 
const ImagePreview = () => {
  const [selectedImage, setSelectedImage] = useState(null);
  const [imagePreview, setImagePreview] = useState(null);
 
  const handleImageSelect = (event) => {
    const file = event.target.files[0];
    if (file && file.type.startsWith('image/')) { // Validate file type
      setSelectedImage(file);
      previewImage(file);
    } else {
      alert('Please select an image file (JPG, PNG, etc.)');
    }
  };
 
  const previewImage = (file) => {
    const reader = new FileReader();
    reader.onload = (event) => {
      setImagePreview(event.target.result); // Base64 URL
    };
    reader.readAsDataURL(file);
  };
 
  return (
    <div className="image-preview">
      <h3>Image Upload & Preview</h3>
      <input
        type="file"
        onChange={handleImageSelect}
        accept="image/*" // Restrict to images
        id="image-input"
      />
      <label htmlFor="image-input" className="btn">
        Select Image
      </label>
 
      {selectedImage && (
        <p>Selected: {selectedImage.name} ({Math.round(selectedImage.size / 1024)} KB)</p>
      )}
 
      {/* Display image preview */}
      {imagePreview && (
        <div className="preview-container">
          <h4>Preview:</h4>
          <img
            src={imagePreview}
            alt="Preview"
            style={{ maxWidth: '300px', maxHeight: '300px' }}
          />
        </div>
      )}
    </div>
  );
};
 
export default ImagePreview;

Understanding and Fixing the "C:fakepath" Issue#

What Causes "C:fakepath"?#

When you select a file using <input type="file" />, the browser intentionally obscures the full file path for security reasons. For example, if you select C:\Users\YourName\Documents\file.txt, the browser will return C:fakepath\file.txt instead of the real path. This prevents malicious websites from accessing sensitive information about the user’s file system.

You might encounter this issue if you mistakenly use the input’s value property to display the file path:

// ❌ Problematic: Uses input's value (shows C:fakepath)
<input type="file" onChange={(e) => console.log(e.target.value)} />
// Output: "C:fakepath\file.txt"

The Fix: Use File.name Instead#

The File object (stored in event.target.files[0]) contains a name property that returns the actual filename (without the path). This is the safe and correct way to display the selected file:

// ✅ Correct: Use the File object's name property
const handleFileSelect = (event) => {
  const file = event.target.files[0];
  if (file) {
    console.log('Real filename:', file.name); // Output: "file.txt"
  }
};

Example: Before and After#

Before (Using input.value)After (Using File.name)
console.log(e.target.value)console.log(selectedFile.name)
Output: C:fakepath\document.txtOutput: document.txt

Why This Works:#

Browsers restrict access to the full file path, but they do expose the filename via the File object. Thus, always use selectedFile.name to display the file name to the user.

Advanced Tips#

1. Multiple File Uploads#

To allow users to select multiple files, add the multiple attribute to the input:

<input type="file" multiple onChange={handleMultipleFiles} />
 
const handleMultipleFiles = (event) => {
  const files = Array.from(event.target.files); // Convert FileList to array
  console.log('Selected files:', files); // Array of File objects
};

2. Validate File Types and Sizes#

Prevent invalid uploads by checking file type and size before processing:

const validateFile = (file) => {
  // Allowed types: .txt, .md (MIME types)
  const allowedTypes = ['text/plain', 'text/markdown'];
  const maxSize = 5 * 1024 * 1024; // 5MB
 
  if (!allowedTypes.includes(file.type)) {
    alert('Invalid file type. Allowed: .txt, .md');
    return false;
  }
 
  if (file.size > maxSize) {
    alert('File too large! Max size: 5MB');
    return false;
  }
 
  return true;
};
 
// Usage in handleFileSelect:
if (file && validateFile(file)) {
  setSelectedFile(file);
}

3. Reusable File Upload Hook#

Create a custom hook (e.g., useFileUpload) to reuse file upload logic across components:

import { useState } from 'react';
 
const useFileUpload = () => {
  const [files, setFiles] = useState([]);
  const [error, setError] = useState(null);
 
  const handleFileSelect = (event) => {
    const selectedFiles = Array.from(event.target.files);
    setFiles(selectedFiles);
    setError(null);
  };
 
  return { files, handleFileSelect, error };
};
 
// Usage in a component:
const MyComponent = () => {
  const { files, handleFileSelect } = useFileUpload();
 
  return (
    <input type="file" multiple onChange={handleFileSelect} />
  );
};

4. Third-Party Libraries#

For advanced features like drag-and-drop uploads or progress bars, use libraries like:

Conclusion#

Uploading and reading files in React is straightforward once you understand the basics: use <input type="file" /> to capture files, the FileReader API to read contents, and File.name to avoid the "C:fakepath" issue.

Key takeaways:

  • Select files with input[type="file"] and track them in state.
  • Read contents using FileReader (e.g., readAsText for text, readAsDataURL for images).
  • Fix "fakepath" by displaying File.name instead of the input’s value.

With these tools, you can build robust file upload features in React while adhering to browser security best practices.

References#