Как подкачать имена файлов в Unix?

Какой-либо способ сделать это быстро, не используя временную переменную? В функции существует ли созданный?

Править: Спасибо за парней ответов. Похож я должен разъяснить свой вопрос, но по большей части Вы парни приняли правильно: существует два файла, и имена имен файлов инвертируются.

  • Файл A имеет имя B-name.file
  • Файл B имеет имя A-name.file

Я хотел бы за Файл A быть названным A-name.file и Файлом B, который назовут B-name.file.

Я соглашаюсь, ситуации часто не происходит, но это просто произошло со мной, и я хотел быстрое исправление.

6
задан volni 1 January 2010 в 00:32
поделиться

5 ответов

ок, глупый вопрос, но почему нельзя просто сделать что-то вроде (в сценарии оболочки):

mv $fileA $fileA.$$
mv $fileB $fileA
mv $fileA.$$ $fileB

и да, конечно, он использует временный файл, но более лаконичный, чем другие ответы.

.
5
ответ дан 8 December 2019 в 03:39
поделиться

В Darwin/Mac OS X есть системный вызов exchangedata() :

Функция exchangedata() обменивает содержимое файлов, на которые ссылается path1 и path2 атомарной формой. То есть, все параллельные процессы будут видеть либо пред- или пост-измененное состояние; они никогда не смогут увидеть файлы в непоследовательном состоянии.

Однако, на самом деле, это работает только на нескольких файловых системах, которые специально поддерживают это (например, Apple's HFS и HFS+), и я не видел никаких подобных системных вызовов на других системах. Переносной способ сделать это - использовать третье временное имя файла, и операция не будет атомарной.

.
9
ответ дан 8 December 2019 в 03:39
поделиться

На уровне скриптов оболочки - нет стандартной команды, и переименование подразумевает, по крайней мере, временное имя файла (остерегайтесь файлов на разных файловых системах!).

На уровне кода на языке C нет стандартной функции для подкачки имен файлов на всех машинах - и одним из факторов является проблема работы с файлами на разных файловых системах.

На одной файловой системе:

file1=one-file-name
file2=tother-file
file3=tmp.$$

trap "" 1 2 3 13 15
ln $file1 $file3
rm $file1
ln $file2 $file1
rm $file2
ln $file3 $file2
rm $file3
trap 1 2 3 13 15

Это не совсем корректно - но это полудецентричное приближение, если $file1 и $file2 находятся на одной файловой системе (и я предположил, что $file3 - это имя на одной файловой системе). Исправление его для работы со всеми бородавками ... нетривиально. (Рассмотрим $file1 == $file2, например.)

Код симулирует практически системные вызовы, которые должна была бы сделать программа на Си - ln для сопоставления с link() и rm для сопоставления с unlink(). Более новая (как, например, только двадцатилетняя) функция rename(), вероятно, может быть использована для хорошего эффекта - при условии, что вы поймете, чего она не сделает. Использование команды mv вместо связывания и удаления означает, что при необходимости файлы будут перемещены между файловыми системами; это может быть полезно - или это может означать, что ваше дисковое пространство заполняется, когда вы этого не задумывали. Восстановление из части ошибки также не совсем тривиально.

.
3
ответ дан 8 December 2019 в 03:39
поделиться

Возможно, это можно было бы сделать с:

file_B = fopen(path_b, 'r');
rename(path_a, path_b);

file_B_renamed = fopen(path_a, 'w');
/* Copy contents of file_B into file_B_renamed */
fclose(file_B_renamed);
fclose(file_B);

Можно было бы (я ищу по спецификации POSIX, но я бы на это не ставил) создать жесткую связь с номером inode; которая в конечном итоге сделала бы что-то вроде

file_B = fopen(path_b, 'r');
rename(path_a, path_b);
make_hardlink(file_B, path_a);
1
ответ дан 8 December 2019 в 03:39
поделиться

Что означает "swap fileenames"? Вы говорите о файловой системе или просто о переменных в вашей программе?

Если ваша программа на C++, и у вас два имени файлов в строках, и вы хотите подкачать их, используйте std::swap. Это изменит только переменные в программе:

std::string filenameA("somefilename");
std::string filenameB("othername");

std::swap(filenameA, filenameB);
std::cout << filenameA << std::endl; // prints "othername"

Если у вас на диске два файла, и вы хотите, чтобы имена файлов обменивались друг с другом, то нет, если вы хотите сохранить жесткие ссылки, то нет способа легко это сделать. Если вы просто хотите выполнить "безопасное сохранение", то системный вызов unix rename() засоряет целевой файл исходным файлом атомарной операцией (настолько атомарной, насколько это может быть поддержано базовой файловой системой). Таким образом, вы будете безопасно сохранять:

std::string savename(filename);
savename += ".tmp";
... write data to savename ...
if (::rename(savename.c_str(), filename.c_str()) < 0) {
  throw std::exception("oops!");
}

Если вам действительно нужно поменять местами файлы на диске (скажем, сохранить резервную копию), то введите жесткую ссылку. Замечание: жесткая привязка поддерживается не на всех файловых системах (особенно на некоторых файлообменниках SMB), так что при необходимости вам нужно будет реализовать некоторое резервное копирование. Вам понадобится временный файл с именем , но не любое временное хранилище данных. Хотя вы можете реализовать его вручную с помощью функции link() и unlink() (помните: файлы могут иметь несколько жестких ссылок в UNIX), проще простого использовать функцию rename(). Вы не можете делать подкачку полностью атомически, однако.

предполагая, что старый файл - это "filname.dat", а новый - "filename.dat.bak", вы получите следующее:

::link(oldfile, tempfile);
::rename(newfile, oldfile);
::rename(tempfile, newfile);

Если вы упадете после ссылки, то новые данные будут в новом файле, а старые данные - в старом и временном. При падении после первого переименования новые данные будут в старом файле, а старые данные - в temp-файле (но не в новом!)

.
1
ответ дан 8 December 2019 в 03:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: