R05(2023)/08/3
R05(2023)/08/20 「999999 Project」を追加
macOS Ventura 13.4.1(c)(22F770820d), Xcode Version 14.3.1 (14E300c)
ChatGPT-3.5
Command 実行時に与えられたフォルダパス内のファイルの作成日時、変更日時、アクセス日時、i node 変更日時を表示します。「.」でファイル名が始まるファイルは除外されます。100 個のファイルが入ったフォルダで試しました。また、フォルダ内にフォルダが有る場合の反応は確認していません。
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#define MAX_FILES 100
typedef struct {
char file_path[512];
struct timespec create_time;
struct timespec mod_time;
struct timespec access_time;
struct timespec inode_change_time;
} FileInfo;
int compare_mod_time(const void *a, const void *b) {
const FileInfo *file_info_a = (const FileInfo *)a;
const FileInfo *file_info_b = (const FileInfo *)b;
if (file_info_a->mod_time.tv_sec < file_info_b->mod_time.tv_sec) {
return -1;
} else if (file_info_a->mod_time.tv_sec > file_info_b->mod_time.tv_sec) {
return 1;
} else {
if (file_info_a->mod_time.tv_nsec < file_info_b->mod_time.tv_nsec) {
return -1;
} else if (file_info_a->mod_time.tv_nsec > file_info_b->mod_time.tv_nsec) {
return 1;
} else {
return 0;
}
}
}
void print_time_with_nanoseconds(const struct timespec *timespec) {
struct tm *timeinfo;
char formatted_time[30]; // 2023-08-02 21:10:15.123456789\0
time_t t = timespec->tv_sec;
timeinfo = localtime(&t);
// フォーマットされた時間文字列を作成
strftime(formatted_time, sizeof(formatted_time), "%Y-%m-%d %H:%M:%S", timeinfo);
printf("%s.%09ld\n", formatted_time, timespec->tv_nsec);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <folder_path>\n", argv[0]);
return 1;
}
const char *folder_path = argv[1];
DIR *dir;
struct dirent *entry;
FileInfo file_list[MAX_FILES];
int file_count = 0;
if ((dir = opendir(folder_path)) == NULL) {
perror("Error while opening directory");
return 1;
}
while ((entry = readdir(dir)) != NULL) {
char file_path[512];
snprintf(file_path, sizeof(file_path), "%s/%s", folder_path, entry->d_name);
// ファイル名が「.」で始まる場合はスキップ
if (entry->d_name[0] == '.') {
continue;
}
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
struct stat file_stat;
if (stat(file_path, &file_stat) == -1) {
perror("Error while getting file status");
continue;
}
strcpy(file_list[file_count].file_path, file_path);
file_list[file_count].create_time = file_stat.st_birthtimespec;
file_list[file_count].mod_time = file_stat.st_mtimespec;
file_list[file_count].access_time = file_stat.st_atimespec;
file_list[file_count].inode_change_time = file_stat.st_ctimespec;
file_count++;
}
}
closedir(dir);
// 「Modification Time」でソート
qsort(file_list, file_count, sizeof(FileInfo), compare_mod_time);
for (int i = 0; i < file_count; i++) {
printf("File: %s\n", file_list[i].file_path);
printf("File Creation Time (nanoseconds): ");
print_time_with_nanoseconds(&file_list[i].create_time);
printf("File Modification Time (nanoseconds): ");
print_time_with_nanoseconds(&file_list[i].mod_time);
printf("File Access Time (nanoseconds): ");
print_time_with_nanoseconds(&file_list[i].access_time);
printf("i-node Change Time (nanoseconds): ");
print_time_with_nanoseconds(&file_list[i].inode_change_time);
printf("\n");
}
return 0;
}
せっかくCreation Time をナノ秒単位で取得できるようになったので、なんの役にも立ちませんが、100 万ファイルを作成して「.」以下に「999999」が含まれたファイルがいくつ有るかを表示するCommand Line Tool を作成して試して見ました。100 万ファイルを作成するに当たりRAM Disk を使いました。ファイルの中身は一桁の乱数としました。Source Code を下記に示します。試す際には自己責任で。またアンチウイルスアプリケーションはOFF がよいです。Spotlight の対象からもRAM Disk を外しましょう。同一名のファイルが存在する場合は、先に消去します。なので二度目は時間がかかります。二度目以降試す場合はRAM Disk をumount してDisk を再作成したほうが早いです。100 万ファイルをrm Command で消すのは時間がかかります。
使った言語はC++ です。
//
// main.cpp
// 999ProjectC++
//
// Created by niki on 2023/08/16.
//
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstring>
#include <vector>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <ctime>
#include <cstdlib>
#include <algorithm>
int compare(const void *a, const void *b) {
return strcmp(*(const char **)a, *(const char **)b);
}
void deleteExistingFiles(const char *folderPath) {
struct dirent *entry;
DIR *dp = opendir(folderPath);
if (dp != NULL) {
while ((entry = readdir(dp))) {
if (strncmp(entry->d_name, "0000001.txt", 10) >= 0 && strncmp(entry->d_name, "1000000.txt", 11) <= 0) {
char filePath[1024];
snprintf(filePath, sizeof(filePath), "%s/%s", folderPath, entry->d_name);
remove(filePath);
}
}
closedir(dp);
}
}
void createFiles(const char *folderPath, int numFiles) {
struct timeval now;
gettimeofday(&now, NULL);
for (int i = 1; i <= numFiles; i++) {
char filePath[1024];
snprintf(filePath, sizeof(filePath), "%s/%07d.txt", folderPath, i);
std::ofstream file(filePath);
if (file.is_open()) {
file << rand() % 10 << "\n"; // 1桁の乱数を書き込む
file.close();
}
}
}
void displayFileCreationTimes(const char *folderPath) {
struct dirent *entry;
std::vector<std::string> fileNames;
DIR *dp = opendir(folderPath);
if (dp != NULL) {
while ((entry = readdir(dp))) {
if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
fileNames.push_back(entry->d_name);
}
}
closedir(dp);
}
// ファイル名をソート
std::sort(fileNames.begin(), fileNames.end());
for (const std::string &fileName : fileNames) {
std::string filePath = folderPath + std::string("/") + fileName;
struct stat fileStat;
if (stat(filePath.c_str(), &fileStat) == 0) {
struct timespec createTime;
createTime.tv_sec = fileStat.st_birthtimespec.tv_sec;
createTime.tv_nsec = fileStat.st_birthtimespec.tv_nsec;
long nanoSec = createTime.tv_nsec;
std::string nanoStr = std::to_string(nanoSec);
if (nanoStr.find("999999") != std::string::npos) {
std::cout << fileName << " ." << nanoStr << " nanoSec" << std::endl;
}
}
}
}
int main() {
const char *folderPath = "/Volumes/ramdisk/temp999";
deleteExistingFiles(folderPath);
createFiles(folderPath, 1000000);
displayFileCreationTimes(folderPath);
return 0;
}