如何转换所有,txt文件在文件夹中从utf16到utf8,他们可以在R读取?

ddarikpa  于 2023-05-04  发布在  其他
关注(0)|答案(1)|浏览(344)

bounty还有4天到期。回答此问题可获得+50声望奖励。jc2525正在寻找一个答案从一个有信誉的来源

就像标题说的那样。..我如何将代码嵌入到我的脚本中,将文件夹中的所有文件从utf16更改为utf8,以使R更容易阅读?

afdcj2ne

afdcj2ne1#

R可以读取utf-16文件

R能够读取utf-16文件,因此可能不需要转换它们。但是,如果你想转换它们,这里是:
1.一个R方法,用于将目录中的所有utf-16编码文件复制到一个新的utf-8编码文件夹中。这需要一次将每个文件读入RAM,这对于大文件可能会有问题。
1.更改文件目录编码的本机操作系统方法列表(Linux/Mac和Windows):

  1. Linux/Mac方法使用iconv转换文件流,即。e.避免将整个文件一次存储在存储器中。
  2. Windows纯PowerShell方法使用Get-Content,它一次读取整个文件。
  3. Windows PowerShell方法与一些嵌入式C#逐行流式传输文件。
    1.如何使用base R、data.tabletidyverseutf-16 csv文件读入R的摘要。如果你只是想把一些文件读入R,就没有必要复制它们的utf-8编码,这可能是正确的方法。

1. R函数更改文件编码

你可以写一个R函数,在utf-16中读入一个文件,然后在utf-8中写出:

convert_file_to_utf8 <- function(in_file, out_file, encoding = "utf-16") {
    in_file_conn <- file(in_file, encoding = encoding)
    txt <- readLines(in_file_conn)
    close(in_file_conn)

    # Create out directory
    if (!dir.exists(dirname(out_file))) dir.create(dirname(out_file))

    # Write file with new encoding
    out_file_conn <- file(out_file, encoding = "utf-8")
    writeLines(txt, out_file_conn)
    close(out_file_conn)
}

如果你想对整个目录执行此操作,那么你可以编写另一个函数来调用此函数:

create_utf8_dir <- function(in_dir = "./utf16dir/", out_dir = "./utf8dir/") {
    files <- dir(in_dir, full.names = TRUE)
    for (in_file in files) {
        out_file <- sub(in_dir, out_dir, in_file, fixed = TRUE)
        convert_file_to_utf8(in_file, out_file)
    }
}

运行create_utf8_dir()将把"./utf16dir/"目录的utf-16编码内容复制到名为"./utf8dir/"的目录(如果不存在,将创建该目录)。

2.本机操作系统更改文件编码的方法

但是,如果文件很大,那么一次读取每个完整文件的R方法可能会使用大量的RAM。

2.1 bash

如果你使用Linux/Mac,我会使用iconv,它可以change a file encoding while streaming the file,i。e.从不将整个文件内容保存在RAM中。对于一个文件,您可以执行以下操作:

iconv -f UTF-16 -t UTF-8 mtcars.csv > mtcars_utf8.csv

要复制R代码的行为,您可以执行以下操作:

IN_ENCODING=UTF16
OUT_ENCODING=UTF8
OUT_DIR=utf8dir
for f in ./utf16dir/*; do
    basename="$(basename ${f%.*})"
    extension=${f##*.}  
    outfile="./$OUT_DIR/$basename$OUT_ENCODING.$extension"
    echo $outfile
    iconv -f $IN_ENCODING -t $OUT_ENCODING $f > $outfile
done

2.2 PowerShell

2.2.1纯PowerShell

如果您使用的是Windows,则可以使用以下模式:

(Get-Content -path mtcars.csv) | Set-Content -Encoding ASCII -Path mtcarsutf8.csv

PowerShell中R和bash脚本的等价形式是:

$in_dir = "./utf16dir/"
$out_dir = "./utf8dir/"

If (!(test-path -PathType container $out_dir)) {
    New-Item -ItemType Directory -Path $out_dir
}

Get-ChildItem $in_dir | 
Foreach-Object {

    $outfile = $out_dir + $_.BaseName + "_utf8" + $_.Extension
    Write-Output $outfile

    (Get-Content -path $_.FullName) | Set-Content -Encoding ASCII -Path $outfile
}

这将再次将目录"./utf16dir/"utf-16编码内容复制到名为"./utf8dir/"的目录(如果不存在,它将创建该目录),并将"_utf8"附加到文件名。
这种方法存在缺点:
1.我将编码设置为ASCII,它是utf-8的子集。这里没问题,因为我知道所有的字符都是ASCII字符。如果不是这样,您可以将ASCII更改为UTF-8。但是,Windows使用utf-8-bom。删除字节顺序标记(BOM)并不完全简单-如果您有非ASCII字符,请参阅here
1.这就像R方法一样,一次将整个文件读入RAM。

2.2.2 Powershell内嵌C#

您可以通过使用C#within Powershell逐行读取utf-16编码的文件,然后写出utf-8文件来克服这两个限制:

$code = @"
using System;
using System.IO;
namespace ProcessLargeFile
{
    public class Program
    {
        static void ConvertLine(string line, StreamWriter sw)
        {
            sw.WriteLine(line);
        }
        public static void ConvertFile(string path, string inDir, string outDir) {
            StreamReader sr = new StreamReader(File.Open(path, FileMode.Open));
            string outPath = path.Replace(inDir, outDir);
            Console.WriteLine(outPath);
            StreamWriter sw = new StreamWriter(File.Open(outPath, System.IO.FileMode.Append));
            try {
                while (!sr.EndOfStream){
                    string line = sr.ReadLine();
                    ConvertLine(line, sw);
                }
            } finally {
                sr.Close();
                sw.Close();
            }
        }
        static void ConvertDir(string inDir, string outDir) {
            string[] filePaths = Directory.GetFiles(inDir);
            Directory.CreateDirectory(outDir);
            foreach(string file in filePaths)
            {
                ConvertFile(file, inDir, outDir);
            }
        }
        public static void Main(string[] args){
            string inDir = args[0];
            string outDir = args[1];
            ConvertDir(inDir, outDir);
        }
    }
}
"@
Add-Type -TypeDefinition $code -Language CSharp
[ProcessLargeFile.Program]::Main(@("utf16dir/", "utf8dir/"))

这再次将"utf16dir/"的内容复制到"utf8dir/"。您可以通过更改最后一行中的参数来更改输入和输出目录。这种方法对文件进行流式处理并写出纯utf-8(没有BOM)。

3. base R,data.table和tidyverse方法来读取utf-16文件

在你的问题中,你说你希望改变编码,以使R更容易读取文件。如您所见,R能够读取utf-16文件,只要您在创建与file()的文件连接时指定编码即可。我将在这里介绍如何使用base R和流行的替代方案读取utf-16 csv文件。例如,假设您正在尝试读取以下文件:

in_file <- "./utf16dir/mtcars.csv"

base R

in_file_conn <- file(in_file, encoding = encoding)
read.csv(text = readLines(in_file_conn))

data.table

in_file_conn <- file(in_file, encoding = encoding)
data.table::fread(
    text = readLines(in_file_conn)
)

读取

readr::read_csv(
    in_file,
    locale = readr::locale(encoding = "utf-16")
)

根据您的最终目标,您可能只希望读入utf-16编码的文件,而不是复制目录中的所有文件。

相关问题