2011-01-23 5 views
12

Rには、ファイルをtarおよびgzipできる便利なクロスプラットフォームtar()関数があります。この関数は、ディレクトリ全体をタールアップするように設計されているようです。私はこの機能を使って、ディレクトリの一部、または単一のファイルを圧縮して圧縮することを望んでいました。しかし、私はこれをするように見えることはできません。私は、現在の作業ディレクトリに1つのCSVファイルをアップタール、次の期待していた。特定のファイルに対してRの内部tar関数を使用する

tar("tst.tgz", "myCsv.csv", compression="gzip") 

だから、ディレクトリのタール()関数を使用するだけで可能ですか?

一時的に、一時ディレクトリを作成し、ファイルをコピーしてから、一時ディレクトリ全体をタールします。しかし、私は少しシンプルな解決策を望んでいた。それは大容量のファイルには時間がかかりますが、ファイルをコピーする必要はありません。

+2

ファイルが1つしかない場合は、gzfileを使用しないでください。 – hadley

+0

私は本当にもっとしたいです...しかし、1つで始めることを喜んで –

答えて

10

あなたがJDを記述しているとは考えられません。 files引数はpath引数のlist.filesに渡され、その結果、個々のファイルではなくディレクトリ内のファイルをタールアップして動作します。

tar()の内部でlist.files()を呼び出すことで、内部機能を編集する準備ができている場合は、tar()を自由に作成できます。ちょっとした手品がtar2()関数を生成しました。これには、list.files()が返す追加の引数があります。この機能を使用して、我々はあなたがこのような呼び出しを経由して欲しいものを達成することができます:あなたは"bar.csv"を含む名前のファイルを非表示になっていない限り

tar2("foo.tar", path = ".", pattern = "bar.csv", recursive = FALSE, 
    full.names = FALSE, all.files = FALSE) 

all.files = FALSEすることは可能性が冗長です。

recursive = FALSEビットは、現在のディレクトリ以外の場所を検索する機能を停止します。これは、作業ディレクトリに多数のファイルとサブフォルダがある場合に検索を高速化します。

ビットはfull.names = FALSEビットです。この場合、TRUEの場合、list.files()は一致するファイル名を"./bar.csv"と返します。tar()は、タールボール内のフォルダに収まります。これをFALSEに設定すると、list.files()"bar.csv"を返します。したがって、要求されたとおりに1つのCSVファイルでtarballを取得します。あなたは似た名前のファイルを持っているとだけ述べて、ファイル名を検索したい場合

は、^$、とパターンの内側にそれをペグ例:

ここ
tar2("foo.tar", path = ".", pattern = "^bar.csv$", recursive = FALSE, 
    full.names = FALSE, all.files = FALSE) 

tar2()として修正tar()機能は次のとおりです。

tar2 <- function (tarfile, files = NULL, compression = c("none", "gzip", 
    "bzip2", "xz"), compression_level = 6, tar = Sys.getenv("tar"), 
    pattern = NULL, all.files = TRUE, recursive = TRUE, full.names = TRUE) 
{ 
    if (is.character(tarfile)) { 
     TAR <- tar 
     if (nzchar(TAR) && TAR != "internal") { 
      flags <- switch(match.arg(compression), none = "cf", 
       gzip = "zcf", bzip2 = "jcf", xz = "Jcf") 
      cmd <- paste(TAR, flags, shQuote(tarfile), paste(shQuote(files), 
       collapse = " ")) 
      return(invisible(system(cmd))) 
     } 
     con <- switch(match.arg(compression), none = file(tarfile, 
      "wb"), gzip = gzfile(tarfile, "wb", compress = compression_level), 
      bzip2 = bzfile(tarfile, "wb", compress = compression_level), 
      xz = xzfile(tarfile, "wb", compress = compression_level)) 
     on.exit(close(con)) 
    } 
    else if (inherits(tarfile, "connection")) 
     con <- tarfile 
    else stop("'tarfile' must be a character string or a connection") 
    files <- list.files(files, recursive = recursive, all.files = all.files, 
     full.names = full.names, pattern = pattern) 
    bf <- unique(dirname(files)) 
    files <- c(bf[!bf %in% c(".", files)], files) 
    for (f in unique(files)) { 
     info <- file.info(f) 
     if (is.na(info$size)) { 
      warning(gettextf("file '%s' not found", f), domain = NA) 
      next 
     } 
     header <- raw(512L) 
     if (info$isdir && !grepl("/$", f)) 
      f <- paste(f, "/", sep = "") 
     name <- charToRaw(f) 
     if (length(name) > 100L) { 
      if (length(name) > 255L) 
       stop("file path is too long") 
      s <- max(which(name[1:155] == charToRaw("/"))) 
      if (is.infinite(s) || s + 100 < length(name)) 
       stop("file path is too long") 
      warning("storing paths of more than 100 bytes is not portable:\n ", 
       sQuote(f), domain = NA) 
      prefix <- name[1:(s - 1)] 
      name <- name[-(1:s)] 
      header[345 + seq_along(prefix)] <- prefix 
     } 
     header[seq_along(name)] <- name 
     header[101:107] <- charToRaw(sprintf("%07o", info$mode)) 
     uid <- info$uid 
     if (!is.null(uid) && !is.na(uid)) 
      header[109:115] <- charToRaw(sprintf("%07o", uid)) 
     gid <- info$gid 
     if (!is.null(gid) && !is.na(gid)) 
      header[117:123] <- charToRaw(sprintf("%07o", gid)) 
     size <- ifelse(info$isdir, 0, info$size) 
     header[137:147] <- charToRaw(sprintf("%011o", as.integer(info$mtime))) 
     if (info$isdir) 
      header[157L] <- charToRaw("5") 
     else { 
      lnk <- Sys.readlink(f) 
      if (is.na(lnk)) 
       lnk <- "" 
      header[157L] <- charToRaw(ifelse(nzchar(lnk), "2", 
       "0")) 
      if (nzchar(lnk)) { 
       if (length(lnk) > 100L) 
        stop("linked path is too long") 
       header[157L + seq_len(nchar(lnk))] <- charToRaw(lnk) 
       size <- 0 
      } 
     } 
     header[125:135] <- charToRaw(sprintf("%011o", as.integer(size))) 
     header[258:262] <- charToRaw("ustar") 
     header[264:265] <- charToRaw("0") 
     s <- info$uname 
     if (!is.null(s) && !is.na(s)) { 
      ns <- nchar(s, "b") 
      header[265L + (1:ns)] <- charToRaw(s) 
     } 
     s <- info$grname 
     if (!is.null(s) && !is.na(s)) { 
      ns <- nchar(s, "b") 
      header[297L + (1:ns)] <- charToRaw(s) 
     } 
     header[149:156] <- charToRaw(" ") 
     checksum <- sum(as.integer(header))%%2^24 
     header[149:154] <- charToRaw(sprintf("%06o", as.integer(checksum))) 
     header[155L] <- as.raw(0L) 
     writeBin(header, con) 
     if (info$isdir || nzchar(lnk)) 
      next 
     inf <- file(f, "rb") 
     for (i in seq_len(ceiling(info$size/512L))) { 
      block <- readBin(inf, "raw", 512L) 
      writeBin(block, con) 
      if ((n <- length(block)) < 512L) 
       writeBin(raw(512L - n), con) 
     } 
     close(inf) 
    } 
    block <- raw(512L) 
    writeBin(block, con) 
    writeBin(block, con) 
    invisible(0L) 
} 
+0

私はタール()にしようとしていた気がしました。確認してくれてありがとう;) –

+0

@JD Long異なる引数を受け入れるように 'tar()'関数を編集するとできます。 1つのソリューションのための私の更新された答えを見てくださいパッチとなるはずの –

+0

。うんざり細工Gavin。 –

1

list.files()(またはその同義語dir())を適切なパターンで実行して、files=が要求する文字ベクトルを与えるとどうなりますか?ヘルプMethinksが明確である:

Arguments:

tarfile: The pathname of the tarfile: tilde expansion (see ‘path.expand’) will be performed. Alternatively, a connection that can be used for binary writes.

files: A character vector offilepaths to be archived: the default is to archive all files under the current directory.

+0

ええ、私は私の質問でもっと冗長されている必要があります。私はそれから始めました...質問を1つのファイルの単純なケースに変更してみましょう。これは私が尋ね始めたものですが、その後、ワイルドカードケースの中間質問に切り替えました。 –

3

は、これはさらにtar1コードを簡素化し、再び改訂されました。また、tar1はディレクトリなしで1つのファイルを出力することも、ディレクトリなしで複数のファイルを出力することもできます。本質的には、tarのRでlist.filesを使用する際のバグを回避する必要があります。list.filestar1で再定義することでこれを行います。

tarの環境を操作するラインは、実際にその環境にコピーtarが実行されるとき、それは最初list.filesのためにそこに見えるようにtar1内の環境ですtarのコピーを作成します。新しい環境でtarのコピーを作成していない場合は、再定義を無視して、Rのベースにlist.filesを使用していました。

未満tar1は、レベルが1つのコンポーネント(つまり、ディレクトリがない単一のファイルまたはファイルのセット)を持つtarファイルを生成するコマンドのバリエーションです(tar)。すべてのファイルがカレントディレクトリにあるものとします。

tar1の定義に続いて、2つのファイルを作成し、最初のファイルとその両方のファイルを含むアーカイブを作成してテストします。

# tar a single file 
tar1 <- function(...) { 
    list.files <- function(...) ..1 
    environment(tar) <- environment() 
    tar(...) 
} 

# test - first create test files, then some test runs of tar1 
cat("a", file = "a.csv") 
cat("b", file = "a.csv") 

tar1("tst.tgz", "a.csv", "gzip") 
tar1("tst2.tgz", Sys.glob("*.csv"), "gzip") 
+0

私のシステムで動作します。私はそれを示すために出力を投稿に追加しました。 –

+0

@JD Longは、彼のQを単一の記述されたcsvファイルをタールしようとすることに単純化しました。 –

+0

私は答えの最初の文章で説明したように答えを改訂しました。 –

関連する問題