diff --git a/NEWS.md b/NEWS.md index fe872d718c..23ba19c0c4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -10,6 +10,8 @@ 1. Custom binary operators from the `lubridate` package now work with objects of class `IDate` as with a `Date` subclass, [#6839](https://github.com/Rdatatable/data.table/issues/6839). Thanks @emallickhossain for the report and @aitap for the fix. +2. `fwrite(compress="gzip")` once again produces a gzip header when the column names are missing or disabled, [@6852](https://github.com/Rdatatable/data.table/issues/6852). Thanks @maxscheiber for the report and @aitap for the fix. + ## NOTES 1. Continued work to remove non-API C functions, [#6180](https://github.com/Rdatatable/data.table/issues/6180). Thanks Ivan Krylov for the PRs and for writing a clear and concise guide about the R API: https://aitap.codeberg.page/R-api/. diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index 1969472943..3e3efa3c3b 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -10024,10 +10024,13 @@ if (!haszlib()) { fwrite(DT, file=f3<-tempfile(), compress="gzip") # compress to filename not ending .gz fwrite(DT, file=f4<-tempfile(), compress="gzip", compressLevel=1) # test compressLevel fwrite(DT, file=f5<-tempfile(), compress="gzip", compressLevel=9) + # col.names=FALSE must not disable gzip header, #6852 + fwrite(DT, file=f6<-tempfile(), compress="gzip", col.names=FALSE) test(1658.441, file.info(f3)$size, file.info(f1)$size) test(1658.442, file.info(f4)$size >= file.info(f1)$size) test(1658.443, file.info(f1)$size >= file.info(f5)$size) - unlink(c(f1,f2,f3,f4,f5)) + test(1658.444, fread(f6, col.names = c("a", "b")), DT) + unlink(c(f1,f2,f3,f4,f5,f6)) } DT = data.table(a=1:3, b=list(1:4, c(3.14, 100e10), c("foo", "bar", "baz"))) test(1658.45, fwrite(DT), output=c("a,b","1,1|2|3|4","2,3.14|1e+12","3,foo|bar|baz")) diff --git a/src/fwrite.c b/src/fwrite.c index 5b01916260..774a227c25 100644 --- a/src/fwrite.c +++ b/src/fwrite.c @@ -829,9 +829,28 @@ void fwriteMain(fwriteMainArgs args) zbuffSize / MEGA, nth, errno, strerror(errno)); // # nocov end } - } + len = 0; + crc = crc32(0L, Z_NULL, 0); -#endif + if (f != -1) { + // write minimal gzip header, but not on the console + static const char header[] = "\037\213\10\0\0\0\0\0\0\3"; + int ret0 = WRITE(f, header, (sizeof header) - 1); + compress_len += (sizeof header) - 1; + + if (ret0 == -1) { + // # nocov start + int errwrite = errno; // capture write errno now in case close fails with a different errno + CLOSE(f); + free(buffPool); + free(zbuffPool); + deflateEnd(&strm); + STOP(_("Failed to write gzip header. Write returned %d"), errwrite); + // # nocov end + } + } + } +#endif // #NOZLIB // write header @@ -873,15 +892,10 @@ void fwriteMain(fwriteMainArgs args) *ch = '\0'; DTPRINT("%s", buff); // # notranslate } else { - int ret0=0, ret1=0, ret2=0; + int ret1=0, ret2=0; #ifndef NOZLIB if (args.is_gzip) { char* zbuff = zbuffPool; - // write minimal gzip header - char* header = "\037\213\10\0\0\0\0\0\0\3"; - ret0 = WRITE(f, header, 10); - compress_len += 10; - crc = crc32(0L, Z_NULL, 0); size_t zbuffUsed = zbuffSize; len = (size_t)(ch - buff); @@ -898,7 +912,7 @@ void fwriteMain(fwriteMainArgs args) #ifndef NOZLIB } #endif - if (ret0 == -1 || ret1 || ret2 == -1) { + if (ret1 || ret2 == -1) { // # nocov start int errwrite = errno; // capture write errno now in case close fails with a different errno CLOSE(f); @@ -906,13 +920,18 @@ void fwriteMain(fwriteMainArgs args) #ifndef NOZLIB free(zbuffPool); #endif - if (ret0 == -1) STOP(_("Failed to write gzip header. Write returned %d"), ret0); - else if (ret1) STOP(_("Failed to compress gzip. compressbuff() returned %d"), ret1); + if (ret1) STOP(_("Failed to compress gzip. compressbuff() returned %d"), ret1); else STOP(_("%s: '%s'"), strerror(errwrite), args.filename); // # nocov end } } } +#ifndef NOZLIB + else { + // was unconditionally initialized for zbuffSize, not used for header + deflateEnd(&strm); + } +#endif if (verbose) DTPRINT(_("Initialization done in %.3fs\n"), 1.0*(wallclock()-t0));