Optimize ReadFileToStringWithMaxSize function
GetFileSize can be used to estimate buffer size if file size is
available. So use it as a hint for buffer size for file reading.
Also avoid latest fread syscall in reading loop using feof.
Bug: 821262
Change-Id: I7dc30483a2f95d4da2c0d3cb0049941d2634a281
Reviewed-on: https://chromium-review.googlesource.com/958861
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#559168}
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
index 6fd5dd8..109cb229c 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -136,27 +136,52 @@
return false;
}
- const size_t kBufferSize = 1 << 16;
- std::unique_ptr<char[]> buf(new char[kBufferSize]);
- size_t len;
- size_t size = 0;
- bool read_status = true;
-
// Many files supplied in |path| have incorrect size (proc files etc).
- // Hence, the file is read sequentially as opposed to a one-shot read.
- while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
- if (contents)
- contents->append(buf.get(), std::min(len, max_size - size));
+ // Hence, the file is read sequentially as opposed to a one-shot read, using
+ // file size as a hint for chunk size if available.
+ constexpr int64_t kDefaultChunkSize = 1 << 16;
+ int64_t chunk_size;
+#if !defined(OS_NACL_NONSFI)
+ if (!GetFileSize(path, &chunk_size) || chunk_size <= 0)
+ chunk_size = kDefaultChunkSize - 1;
+ // We need to attempt to read at EOF for feof flag to be set so here we
+ // use |chunk_size| + 1.
+ chunk_size = std::min<uint64_t>(chunk_size, max_size) + 1;
+#else
+ chunk_size = kDefaultChunkSize;
+#endif // !defined(OS_NACL_NONSFI)
+ size_t bytes_read_this_pass;
+ size_t bytes_read_so_far = 0;
+ bool read_status = true;
+ std::string local_contents;
+ local_contents.resize(chunk_size);
- if ((max_size - size) < len) {
+ while ((bytes_read_this_pass = fread(&local_contents[bytes_read_so_far], 1,
+ chunk_size, file)) > 0) {
+ if ((max_size - bytes_read_so_far) < bytes_read_this_pass) {
+ // Read more than max_size bytes, bail out.
+ bytes_read_so_far = max_size;
read_status = false;
break;
}
+ // In case EOF was not reached, iterate again but revert to the default
+ // chunk size.
+ if (bytes_read_so_far == 0)
+ chunk_size = kDefaultChunkSize;
- size += len;
+ bytes_read_so_far += bytes_read_this_pass;
+ // Last fread syscall (after EOF) can be avoided via feof, which is just a
+ // flag check.
+ if (feof(file))
+ break;
+ local_contents.resize(bytes_read_so_far + chunk_size);
}
read_status = read_status && !ferror(file);
CloseFile(file);
+ if (contents) {
+ contents->swap(local_contents);
+ contents->resize(bytes_read_so_far);
+ }
return read_status;
}