Использование go 1.21.4 windows/adm64
У меня возникла интересная проблема при попытке заархивировать файлы с помощью библиотеки go archive/zip. Файлы все записываются в архив, но Windows сообщает, что zip-файл недействителен. Я могу открыть архив в 7-Zip, и он показывает «Упакованный размер», но не «Размер» для последнего файла, добавленного в архив, и CRC 00000000 для этого файла.
Возможно ли, что файл архива закрывается до того, как последний файл будет полностью записан?
func zipFiles(clipFolder string, zipName string, files []string) int {
archive, err := os.Create(zipName)
if err != nil {
_ = elog.Errorf("Error creating %s: %s", zipName, err.Error())
return 0
}
defer archive.Close()
writer := zip.NewWriter(archive)
zipped := 0
for _, file := range files {
zipped += writeFileToArchive(writer, clipFolder, file)
}
}
return zipped
}
// writeFileToArchive adds a file to the zip archive and returns the number of files added (0 or 1)
func writeFileToArchive(writer *zip.Writer, path string, filename string) int {
w, err := writer.Create(filename)
if err != nil {
elog.Warnf("could not add %s to archive", filename)
return 0
}
fullPath := filepath.Join(path, filename)
source, err := os.Open(fullPath)
if err != nil {
elog.Warnf("could not open %s file for reading", fullPath)
return 0
}
defer source.Close()
_, err = io.Copy(w, source)
if err != nil {
elog.Warnf("could not copy %s into archive", filename)
return 0
}
_ = writer.Flush()
return 1
}
Я добавил вызов write.Flush() после добавления каждого файла в архив, но это не помогает. И я пробовал записывать разное количество файлов — всегда последний файл не обрабатывается должным образом.





Вы не закрываетесь writer. Закрыть:
завершает запись zip-файла, записывая центральный каталог. Он не закрывает основной писатель.
Итак, с вашим кодом центральный каталог не записывается, это то, к чему пытается получить доступ Windows. ZIP-файлы имеют как центральный каталог (в конце файла), так и локальный заголовок для каждого файла, я предполагаю, что 7zip читает локальные заголовки.
Чтобы это исправить, закройте модуль записи (рекомендуется проверить наличие ошибок!):
if err = writer.Close(); err != nil {
_ = elog.Errorf("Error closing %s: %s", zipName, err.Error())
return 0
}
Спасибо, британцы! Я не осознавал, что закрытие архива само по себе не приведет к закрытию основного средства записи. Добавление явного метода Close() для автора помогло.