【操作系统原理】—— 文件系统编程

简介: 【操作系统原理】—— 文件系统编程

实验相关知识

文件系统编程

     文件系统编程是指在编程过程中使用文件系统的相关功能,包括创建、读取、写入、删除文件,以及对目录的操作等。不同的操作系统提供不同的文件系统接口和系统调用,因此文件系统编程的具体实现方式可能会有所不同。以下是在类Unix/Linux环境下进行文件系统编程的一些基本操作和概念:

打开文件:

     使用 open 系统调用打开文件。该调用返回一个文件描述符,之后的读写操作将使用该描述符。

#include <fcntl.h>
int fd = open("filename.txt", O_RDONLY);  // 以只读方式打开文件

读写文件:

     使用 read 和 write 等系统调用进行文件读写操作。

#include <unistd.h>
char buffer[100];
ssize_t bytesRead = read(fd, buffer, sizeof(buffer));  // 从文件中读取数据
ssize_t bytesWritten = write(fd, buffer, bytesRead);   // 写入数据到文件

关闭文件:

     使用 close 系统调用关闭文件。

#include <unistd.h>
close(fd);  // 关闭文件

创建和删除文件:

     使用 creat 或 open 系统调用创建文件。使用 unlink 系统调用删除文件。

#include <fcntl.h>
#include <unistd.h>
int newFile = creat("newfile.txt", 0644);  // 创建文件
unlink("filename.txt");  // 删除文件

文件定位:

     使用 lseek 系统调用移动文件指针,以进行随机访问文件。

#include <unistd.h>
off_t offset = lseek(fd, 0, SEEK_SET);  // 将文件指针移到文件开头

目录操作:

     使用 opendir、readdir、closedir 等系统调用进行目录操作。

#include <dirent.h>
DIR *dir = opendir("/path/to/directory");  // 打开目录 struct dirent
*entry = readdir(dir);       // 读取目录项 closedir(dir);                             // 关闭目录

创建文件,并制定文件访问属性

     在许多编程语言和操作系统中,你可以使用特定的函数或方法来创建文件并指定文件访问属性。以下是一些示例,展示了在不同的编程语言和环境中如何创建文件并设置文件权限或访问属性:

1. C 语言(在 Unix/Linux 环境中)

#include <stdio.h>
#include <fcntl.h>
int main() {
    int fd;
    // 创建文件并设置权限为 0644
    fd = open("example.txt", O_CREAT | O_WRONLY | O_TRUNC, 0644);
    if (fd == -1) {
        perror("Error creating file");
        return 1;
    }
    // 在这里可以写入文件内容,然后关闭文件
    close(fd);
    return 0;
}

2. Python

# 创建文件并设置权限为 0644
with open('example.txt', 'w') as file:
    file.write('Hello, World!\n')
# 可以使用 os 模块来修改文件权限
import os
os.chmod('example.txt', 0o644)

3. Java

import java.io.File;
import java.io.IOException;
public class CreateFile {
    public static void main(String[] args) {
        try {
            // 创建文件并设置权限
            File file = new File("example.txt");
            if (file.createNewFile()) {
                System.out.println("File created: " + file.getName());
                file.setReadable(true);
                file.setWritable(true);
                file.setExecutable(false);
            } else {
                System.out.println("File already exists.");
            }
        } catch (IOException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }
}

4. C# (.NET)

using System;
using System.IO;
class Program
{
    static void Main()
    {
        try
        {
            // 创建文件并设置权限
            using (StreamWriter sw = File.CreateText("example.txt"))
            {
                sw.WriteLine("Hello, World!");
            }
            // 设置文件权限
            File.SetAttributes("example.txt", FileAttributes.Normal);
        }
        catch (Exception e)
        {
            Console.WriteLine("An error occurred: " + e.Message);
        }
    }
}

C库函数和Linux系统调用

C 库函数

定      义: C 库函数是在标准 C 库(如 glibc)中提供的函数,用于执行各种常见的任务。这些函数是用 C 语言编写的,通常被封装在头文件中,可以通过在程序中包含相应的头文件来使用。

特      点: C 库函数提供了高层次的、抽象的接口,使得编程更加方便。这些函数通常涉及到字符串处理、数学计算、文件操作、内存管理等方面的功能。例子包括 printf、scanf、strlen、fopen 等。

调用方式: C 库函数的调用是通过函数调用的方式,直接在程序中调用相应的函数,而不需要进行系统调用。

Linux 系统调用

定      义: 系统调用是操作系统提供的接口,允许用户程序访问底层的操作系统功能。Linux 系统调用是由内核提供的、底层的、直接与硬件交互的接口。这些调用是由内核中断(或陷阱)触发的。

特      点: 系统调用提供了对操作系统核心功能的直接访问,例如进程控制、文件系统访问、网络通信等。它们是操作系统提供的最底层的接口,通常使用 C 语言的 syscall 函数或汇编语言进行调用。

调用方式: 系统调用的调用是通过特殊的指令(例如 int 0x80 或 syscall 汇编指令)来触发内核处理。在 C 程序中,可以通过在程序中使用 syscall 函数或者直接在汇编中使用系统调用指令来调用。

区别

抽象层次: C 库函数提供了更高层次的抽象,隐藏了底层细节,使得编程更加方便。系统调用则提供了直接的、底层的接口,允许对操作系统的底层功能进行更精细的控制。

性      能: 系统调用通常比 C 库函数更为底层,因此在性能上可能更高效。但由于涉及到更多的底层细节,使用系统调用编程可能更加复杂。

可移植性: C 库函数通常是标准的 C 接口,因此更具有可移植性。系统调用则依赖于底层操作系统,可能在不同的操作系统上具有不同的接口。

实验设备与软件环境

安装环境:分为软件环境和硬件环境

硬件环境:内存ddr3 4G及以上的x86架构主机一部

系统环境:windows 、linux或者mac os x

软件环境:运行vmware或者virtualbox

软件环境:Ubuntu操作系统

实验内容

一、文件创建

  1. 编写实验代码file_creat.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
void  create_file(char *filename)
{
    /*创建的文件具有可读可写的属性*/
    if(creat(filename,0666)<0)
  {
        printf("create file %s failure!\n",filename);
        exit(EXIT_FAILURE);
    }
  else
  {
        printf("create file %s success!\n",filename);
    }
}
int main(int argc,char *argv[])
{
    /*判断入参有没有传入文件名 */
    if(argc<2)
  {
        printf("you haven't input the filename,please try again!\n");
        exit(EXIT_FAILURE);
    }
  create_file(argv[1]);    
  exit(EXIT_SUCCESS);
}
  1. 编译以及运行程序file_creat.c
         在终端输入:gcc file_creat.c -o file_creat生成课执行文件file_creat,再输入:./file_creat test.txt运行程序。

运行截图:

     运行了该程序后,可以发现当前目录下产生了test.txt文件。

二、文件拷贝

  1. 编写实验代码file_cp.c
#include <string.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
 
#define BUFFER_SIZE 1024
 
int main(int argc,char **argv)
{
  FILE *from_fd;
  FILE *to_fd;
  long file_len=0;
  char buffer[BUFFER_SIZE];
  char *ptr;
  /*判断入参*/
  if(argc!=3)
  {
    printf("Usage:%s fromfile tofile\n",argv[0]);
    exit(1);
  }
   
  /* 打开源文件 */
  if((from_fd=fopen(argv[1],"rb"))==NULL)
  {
    printf("Open %s Error\n",argv[1]);
    exit(1);
  }
   
  /* 创建目的文件 */
  if((to_fd=fopen(argv[2],"wb"))==NULL)
  {
    printf("Open %s Error\n",argv[2]);
    exit(1);
  }
   
  /*测得文件大小*/
  fseek(from_fd,0L,SEEK_END);
  file_len=ftell(from_fd);
  fseek(from_fd,0L,SEEK_SET);
  printf("from file size is=%ld\n",file_len);
   
  /*进行文件拷贝*/
  while(!feof(from_fd))
  {
    fread(buffer,BUFFER_SIZE,1,from_fd);
    if(BUFFER_SIZE>=file_len)
    {
      fwrite(buffer,file_len,1,to_fd);
    }
    else
    {
      fwrite(buffer,BUFFER_SIZE,1,to_fd);
      file_len=file_len-BUFFER_SIZE;
    }
    memset(buffer, 0, BUFFER_SIZE);
    //bzero(buffer,BUFFER_SIZE); //清零
  }
  fclose(from_fd);
  fclose(to_fd);
  exit(0);
}
  1. 编译以及运行程序file_cp.c
         在终端输入:gcc file_cp.c -o file_cp生成课执行文件file_cp,再输入:./file_cp file_cp.c test.c运行程序。

运行截图:

运行了该程序后,我将file_cp.c拷贝为test.c,可以看到运行程序后文件夹出现了file_cp.c和test.c大小和内容都一样。

三、编写一应用程序实现如下功能:使用open()函数创建一个名为 file. txt,权限为666的文件;并向其中写入字符串“hello world",然后使用read()函数把写入的内容读取出来并在终端上显示输出。

  1. 编写实验代码 file open.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char const *argv[]) {
  int fd,ret;
  char buf[32] = "hello world!",buf2[11] = {0};
  fd = open("file.txt",O_RDWR|O_APPEND|O_CREAT,0666);
  if(fd < 0) {
    printf("open file err\n");
    return -1;
  }
  printf("open success\n");
  ret = write(fd,buf,strlen(buf));
  if(ret < 0) {
    perror("write:");
    return -1;
  }
  printf("write bif = %s\n",buf);
  printf("write count=%d\n",ret);
  close(fd);
  fd = open("file.txt",O_RDWR|O_APPEND|O_CREAT,0666);
  ret = read(fd,buf2,11);
  if(ret < 0) {
    perror("read:");
    return -1;
  }
  printf("read bif2= %s\n",buf2);
  printf("read count=%d\n",ret);
  close(fd);
  return 0;
}
  1. 编译以及运行程序file open.c
         在终端输入:gcc file open.c -o file open生成课执行文件file_cp,再输入:./ file open运行程序。

运行截图:

     运行了该程序后,可以发现当前目录下产生了file.txt文件,并且程序通过使用read()函数把写入的内容字符串“hello world"读取出来并在终端上显示输出了。


相关文章
|
2月前
|
存储 安全 Shell
深入浅出操作系统:从原理到实践
【9月更文挑战第21天】在数字时代的浪潮中,操作系统扮演着至关重要的角色。本文将深入探究操作系统的奥秘,从其基本概念和核心原理出发,逐步引导读者理解操作系统的工作机制。我们将通过生动的例子和实用的代码片段,揭示操作系统如何管理计算机硬件资源、提供用户接口以及确保系统安全与性能优化。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇通往操作系统深层世界的大门。准备好跟随我们的脚步,一起探索这个让计算机变得生动起来的神奇软件吧!
68 8
|
2月前
|
存储 算法 安全
操作系统之文件系统的奥秘
【9月更文挑战第19天】本文将深入探索操作系统中不可或缺的组件——文件系统,揭示其工作原理与实现细节。我们将通过浅显的语言和生动的比喻,一步步解析文件系统如何组织数据、管理存储空间,并确保数据的完整性和安全性。文章不仅适合初学者构建基础概念,也能帮助有经验的开发者更深入地理解文件系统的高级特性。
|
7天前
|
存储 安全 大数据
深入浅出操作系统:文件系统的秘密
【10月更文挑战第35天】本文将揭示文件系统背后的奥秘,从其基本概念到复杂的实现机制。我们将一起探索文件系统的结构和原理,并了解它如何影响我们的日常计算体验。通过简单的例子和比喻,文章旨在使读者对文件系统有一个清晰而深刻的理解,就像甘地所言:“你必须成为你希望在世界上看到的改变。”让我们一起成为理解操作系统的先行者。
|
1月前
|
IDE 开发工具 Android开发
探索移动应用开发之旅:理解移动操作系统与编程实践
【9月更文挑战第36天】在数字化时代的浪潮中,移动应用成为连接用户与数字世界的桥梁。本文将深入探讨移动应用开发的精髓,从移动操作系统的工作原理到实际编程实践,旨在为读者提供一条清晰的道路,以理解和掌握移动应用的开发过程。我们将通过具体示例,揭示如何在不断变化的技术环境中保持应用的性能、安全性和用户体验。无论你是初学者还是有经验的开发者,本文都将为你打开一扇窗,让你一窥移动应用开发的精彩世界。
|
1月前
|
安全 测试技术 数据库
Python编程--sys模块及OS模块简单用例
Python编程--sys模块及OS模块简单用例
|
2月前
|
存储 缓存 文件存储
探索操作系统中的文件系统管理
【9月更文挑战第25天】在数字世界的海洋中,操作系统是指引我们航行的灯塔。它不仅管理着硬件资源,还维护着软件的秩序。本文将深入探讨操作系统中一个至关重要的部分——文件系统管理。我们将从基础概念出发,逐步深入到文件系统的设计与实现,最后通过代码示例来直观展示文件系统的操作。让我们一起揭开文件系统管理的神秘面纱,理解其背后的逻辑与奥秘。
|
2月前
|
Unix Linux Windows
操作系统的演变与基本原理
本文旨在深入探讨操作系统的历史演变过程及其背后的设计原理。通过对不同时期典型操作系统的分析,本文揭示了它们如何响应技术挑战和社会需求的变化。此外,文章还将阐述操作系统的核心功能和关键技术,如进程管理、内存管理和文件系统,并探讨这些技术如何影响计算机系统的性能和可靠性。通过综合历史案例和技术分析,本文希望为读者提供一个全面而深入的理解,为什么操作系统是现代计算不可或缺的基石。
46 1
|
1月前
|
算法 调度 UED
探索操作系统中的多线程编程
【8月更文挑战第78天】在数字世界的复杂迷宫中,操作系统扮演着至关重要的角色。本文旨在揭开操作系统中多线程编程的神秘面纱,引导读者理解其概念、实现及应用。通过深入浅出的方式,我们将探讨如何在程序设计中运用多线程,以及这一技术如何优化软件性能和提升用户体验。文章将结合具体代码示例,展示多线程在实际应用中的魔力。无论你是编程新手还是资深开发者,这篇文章都将为你提供新的视角和思考路径。
|
2月前
|
存储 安全 Linux
探索操作系统:从原理到实践
【9月更文挑战第14天】本文深入探讨了操作系统的核心概念,通过分析其设计原则和功能,揭示了操作系统如何管理计算机硬件资源、提供用户接口并确保系统安全。文章不仅阐述了操作系统的基本原理,还通过实际代码示例展示了如何在操作系统上进行编程,旨在帮助读者更好地理解并应用操作系统知识。
38 1
|
2月前
|
算法 调度 UED
操作系统中的进程管理:原理与实践
在数字世界的心脏跳动着无数进程,它们如同细胞一般构成了操作系统的生命体。本文将深入探讨进程管理的奥秘,从进程的诞生到成长,再到最终的消亡,揭示操作系统如何协调这些看似杂乱无章却又井然有序的活动。通过浅显易懂的语言和直观的比喻,我们将一起探索进程调度的策略、同步机制的重要性以及死锁问题的解决之道。准备好跟随我们的脚步,一起走进操作系统的微观世界,解锁进程管理的秘密吧!
65 6