Это должен быть общий вопрос, который время от времени возникает у всех программистов. Как мне прочитать строку из текстового файла? Тогда следующий вопрос всегда - как мне написать это обратно.
Конечно, большинство из вас используют высокоуровневую инфраструктуру в повседневном программировании (которую можно использовать в ответах), но иногда приятно знать, как это делать и на низком уровне.
Я сам знаю, как сделать это в C
, C ++
и Objective-C
, но было бы удобно увидеть, как это делается на всех популярных языках, если только чтобы помочь нам принять лучшее решение о том, на каком языке делать наш файл. В частности, я думаю, что было бы интересно посмотреть, как это делается на языках манипулирования строками, например: python
, ruby
и, конечно, perl
.
Итак, я полагаю, что здесь мы можем создать ресурс сообщества , чтобы мы могли пометить звездочкой в наших профилях и сослаться на то, когда нам нужно выполнить файловый ввод / вывод на каком-то новом языке. Не говоря уже о воздействии, которое мы все получим на языки, с которыми мы не имеем дело изо дня в день.
Вот как вам нужно ответить:
Пояснение:
C
, C ++
, C #
, Java
, Objective-C
все великолепны.
Если вы знаете, как это сделать в Прологе
, Хаскеле
, Фортране
, Лиспе
или Базовом
] тогда, пожалуйста, продолжайте.
#!/bin/bash
echo 'hello' > fileio.txt
echo 'world' >> fileio.txt
myvar=`tail -n 1 fileio.txt`
echo $myvar
Примеры того, как делать подобные вещи на многих языках (61!), Можно найти на странице ввода-вывода файлов по адресу Rosetta Code . Честно говоря, похоже, что он не отвечает в точности на то, что вы спрашиваете - он имеет дело с вводом-выводом всего файла, - но он довольно близок и охватывает более широкий диапазон, чем этот вопрос в противном случае может привлечь в качестве ответов.
Delphi, стандартный низкоуровневый способ (то есть без TStringList
и других игрушек):
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
f: Text;
fn: string;
ln: string;
begin
fn := ExtractFilePath(ParamStr(0)) + 'fileio.txt';
// Create a new file
FileMode := fmOpenWrite;
AssignFile(f, fn);
try
Rewrite(f);
Writeln(f, 'hello');
Writeln(f, 'world');
finally
CloseFile(f);
end;
// Read from the file
FileMode := fmOpenRead;
AssignFile(f, fn);
try
Reset(f);
Readln(f, ln);
Readln(f, ln);
Writeln(ln);
finally
CloseFile(f);
end;
end.
Поскольку Delphi - это собственный компилятор Win32 , вы также можете использовать Windows API для обработки всех операций ввода-вывода:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows;
var
f: HFILE;
fn: string;
lns: AnsiString;
fsize, amt, i: cardinal;
AfterLine1: boolean;
const
data = AnsiString('hello'#13#10'world');
begin
fn := ExtractFilePath(ParamStr(0)) + 'fileio.txt';
f := CreateFile(PChar(fn), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
try
WriteFile(f, data, length(data), amt, nil);
finally
CloseHandle(f);
end;
f := CreateFile(PChar(fn), GENERIC_READ, 0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
try
fsize := GetFileSize(f, nil);
SetLength(lns, fsize);
ReadFile(f, lns[1], fsize, amt, nil);
for i := 1 to fsize do
case lns[i] of
#10: AfterLine1 := true;
else
if AfterLine1 then
Write(lns[i]);
end;
finally
CloseHandle(f);
end;
end.
И для полноты картины я включаю высокоуровневый подход, хотя сам никогда не использую его:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes;
var
fn: string;
begin
fn := ExtractFilePath(ParamStr(0)) + 'fileio.txt';
with TStringList.Create do
try
Add('hello');
Add('world');
SaveToFile(fn);
finally
Free;
end;
with TStringList.Create do
try
LoadFromFile(fn);
Writeln(Strings[1]);
finally
Free;
end;
end.
f =: 'fileio.txt'
('hello', LF) 1!:2 < f
('world', LF) 1!:3 < f
; 1 { < ;. _2 (1!:1 < f)
Последняя строка читает файл ( 1!: 1
<;. _2
), получает второй элемент ( 1 {
). Затем Monadic ;
используется для распаковки элемента.
Ио
f := File with("fileio.txt")
f open
f write("hello")
f close
f openForAppending
f write("\nworld")
f close
f openForReading
secondLine := f readLines at(1)
f close
write(secondLine)
use 5.012;
use warnings;
use autodie;
# 1 & 2 - create and write line to file
open my $new, '>', 'fileio.txt';
say {$new} 'hello';
close $new;
# 3 - open file to append line
open my $append, '>>', 'fileio.txt';
say {$append} 'world';
close $append;
# 4 - read in second line to input string
my $line = do {
open my $read, '<', 'fileio.txt';
<$read>; # equivalent to: readline $read
<$read>; # last value expression gets returned from do{}
};
print $line; # 5 - print input string!
Выше приведен базовый пример использования open
в современном Perl (т. Е. Три аргумента open, лексические дескрипторы файлов, лучшие практики autodie и say / print) .
Однако в действительности нет необходимости загрязнять пространство имен лексическими переменными $ new
и $ append
(которые содержат дескриптор файла). Поэтому для пунктов 1–3 я, вероятно, почувствовал бы себя более счастливым, выполнив:
{
open my $fh, '>', 'fileio.txt';
say {$fh} 'hello';
}
{
open my $fh, '>>', 'fileio.txt';
say {$fh} 'world';
}
или:
use IO::File; # core module
IO::File->new( 'fileio.txt', 'w' )->print( "hello\n" );
IO::File->new( 'fileio.txt', 'a' )->print( "world\n" );
Обновить re: разъяснение: Вам не нужно повторно открывать текстовый файл после написания первой строки
И без упоминания, нужно ли вам повторно открывать файл для чтения второй строки, поэтому все это можно сделать так:
my $line = do {
open my $fh, '+>', 'fileio.txt';
say {$fh} $_ for qw/hello world/; # or just: say {$fh} "hello\nworld" :)
seek $fh, 0, 0; # rewind to top of file
(<$fh>)[1]; # no need to be lazy with just 2 recs!
};
print $line;
/ I3az /
По историческим причинам, связанным с использованием дискового пространства и памяти ок. 1969, MUMPS позволяет обрезать команды до одного (а иногда и двух) символов, поэтому пример Клейтона выглядел так «странно» (хотя я мог его достаточно легко прочитать). Вот больше о том, что происходит с этой программой MUMPS.
FileIo ; Define a "label" identifying this piece of code (not a function here).
; MUMPS has only process-specific variable scope, so stack local
; variables with the 'New' command.
New File, Line1, Line2
Set File="FILEIO.TXT"
; MUMPS has a concept of a "currently open" device, which "Read" and "Write"
; commands use. Identify a device with the Open command and switch to the
; device with the "Use" command. Get rid of the device with the "Close"
; command.
; Another funny thing here is the "postconditional expression," which in this
; case is "WNS". In this case we pass arguments to the Open command. The
; exact meaning is implementation-specific but if I had to guess, these
; arguments have to do with opening the file for writing, using a newline
; character as a delimiter, etc.
Open File:"WNS" Use File Write "hello" Close File
Open File:"WAS" Use File Write !,"world" Close File ; ! = new line
; Here the "Read" command executes twice on the file, reading two lines into
; the variables "Line1" and "Line2". The Read command is probably aware of the
; line-oriented nature of the file because of the "RS" postconditional.
Open File:"RS" Use File Read Line1,Line2 Close File Write Line2,!
Quit
open('fileio.txt', 'w').write('hello\n')
open('fileio.txt', 'a').write('world\n')
with open('fileio.txt', 'r') as f:
print f.readline() and f.readline(),
Ioke
path = "fileio.txt"
FileSystem withOpenFile(path, fn(f,
f println("hello"))
)
FileSystem withOpenFile(path, fn(f,
f println("world"))
)
FileSystem readLines(path) [1] print
f:`fileio.txt
f 0:/:(*a;a:$`hello`world)
`0:*1_0:f
var fileName = "fileio.txt";
var ForReading = 1;
var ForAppending = 8;
var fso = new ActiveXObject("Scripting.FileSystemObject")
// Create a file and write to it
var file = fso.CreateTextFile(fileName, true /* overwrite if exists */);
file.WriteLine("hello");
file.Close();
// Append to the file
file = fso.OpenTextFile(fileName, ForAppending);
file.WriteLine("world");
file.Close();
// Read from the file
file = fso.OpenTextFile(fileName, ForReading);
file.SkipLine();
var str = file.ReadLine();
file.Close();
WScript.Echo(str);
В последнее время я ненавижу FORTRAN, так что вот:
PROGRAM FILEIO
C WRITES TWO LINES TO A TEXT FILE AND THEN RETRIEVES THE SECOND OF
C THEM
CHARACTER*5 STRIN
OPEN(UNIT=1, FILE='FILEIO.TXT')
WRITE(1,100) 'HELLO'
WRITE (1,100) 'WORLD'
CLOSE(1)
C
OPEN(UNIT=2, FILE='FILEIO.TXT')
READ(2,100) STRIN
READ(2,100) STRIN
WRITE(*,*) STRIN
100 FORMAT(A5)
STOP
END
Edit by ldigas: С другой стороны, мне он скорее нравится
.
(извините, что влез в ваш ответ; мне не хотелось начинать еще один пост про Фортран)
character(10) :: line
open(1,file='fileio.txt',status='replace')
write(1,'("hello"/"world")'); rewind(1);
read(1,'(/a)')line; write(*,'(a)')line
end
(это немного более новый вариант Фортрана... всего каких-то 15-20 лет ;-)
Visual Basic 6.0
open "fileio.txt" for output as #1
write #1, "hello"
close #1
open "fileio.txt" for append as #1
write #1, "world"
close #1
open "fileio.txt" for input as #1
dim strn as string
input #1, strn
input #1, strn
msgbox(strn)
close #1
Program pascalIO;
Var FName, TFile : String[15];
UserFile: Text;
Begin
FName := 'fileio.txt';
Assign(UserFile, FName);
Rewrite(UserFile);
Writeln(UserFile,'hello');
Writeln(UserFile,'world');
Close(UserFile);
Assign(UserFile, FName);
Reset(UserFile);
Readln(UserFile,TFile);
Readln(UserFile,TFile);
Writeln( TFile);
Close(UserFile);
End.
set f [open fileio.txt w+]
puts $f hello
puts $f world
seek $f 0
puts [lindex [split [read $f] \n] 1]
close $f
Io
File with("fileio.txt") open write("hello\n") write("world\n") \
rewind readLines second println
Это самое короткое из решений?
io.open( 'TestIO.txt', 'w' ):write( 'hello' ):write( '\n', 'world' ):close()
aLine = io.open( 'TestIO.txt', 'r' ):read( '*a' ):match( '%C*%c*(.*)' )
print( aLine )
Использование библиотек Adobe AIR:
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
public class fileio
{
public static function doFileIO():void
{
var file:File = File.applicationStorageDirectory.resolvePath("fileio.txt");
var stream:FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeUTFBytes("hello");
stream.writeUTFBytes("\nworld");
stream.close();
stream.open(file, FileMode.READ);
var content:String = stream.readUTFBytes(stream.bytesAvailable);
stream.close();
var input:String = content.split("\n")[1];
trace(input);
}
}
Приложения AIR не могут выполнять запись в свой каталог по соображениям безопасности, поэтому они используют каталог хранилища приложений.
Для получения дополнительной информации (и для загрузки последнего выпуска):
USING: io io.encodings.utf8 io.files ;
"fileio.txt" utf8
[ [ "hello" print ] with-file-writer ]
[ [ "world" print ] with-file-appender ]
[ file-lines last print ] 2tri
Rebol []
write/lines %fileio.txt "hello"
write/lines/append %fileio.txt "world"
print last read/lines %fileio.txt
var FS = require("narwhal/fs");
FS.open("fileio.txt", "w")
.print("hello")
.print("world")
.close()
var stream = FS.open("fileio.txt", "r");
stream.next();
print(stream.next());
stream.close();
Это еще одно конкретное встраивание JavaScript.
#lang racket
(call-with-output-file "fileio.txt"
#:exists 'truncate
(lambda (out)
(fprintf out "hello\n" )))
(call-with-output-file "fileio.txt"
#:exists 'append
(lambda (out)
(fprintf out "world\n" )))
(call-with-input-file "fileio.txt"
(lambda (in)
(read-line in)
(display (read-line in))))
Пример 1:
with open('fileio.txt', 'a') as f:
f.write('hello')
f.write('\nworld')
with open('fileio.txt') as f:
s = f.readlines()[1]
print s
Пример 2 - без диспетчеров контекста:
f = open('fileio.txt', 'a')
f.write('hello')
f.write('\nworld')
f.close()
f = open('fileio.txt')
s = f.readlines()[1]
f.close()
print s
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h> /* For error reporting */
#define BUFFER_SIZE 6
int main (int argc, char *argv[])
{
int fd;
const char HELLO[] = "hello\n";
const char WORLD[] = "world\n";
if ((fd = open ("fileio.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU)) < 0) {
perror ("open");
return 1;
}
if (write (fd, HELLO, sizeof (HELLO)) < 0) {
perror ("write");
return 1;
}
if (write (fd, WORLD, sizeof (WORLD)) < 0) {
perror ("write(2)");
return 1;
}
/* Rewind file */
lseek (fd, 0, SEEK_SET);
/* Read whole file */
int bytes_read;
do {
char buffer[BUFFER_SIZE];
bytes_read = read (fd, buffer, BUFFER_SIZE);
write (0, buffer, bytes_read);
} while (bytes_read > 0);
if (close (fd) != 0) {
perror ("close");
return 1;
}
return 0;
}
use v6;
my $path = 'fileio.txt';
# Open $path for writing.
given open($path, :w) {
.say('hello'); # Print the line "hello\n" to it.
.close; # Close the file.
}
# Open the file for appending.
given open($path, :a) {
.say('world'); # Append the line "world\n" to it.
.close;
}
my $line = lines($path)[1]; # Get the second line. lines returns a lazy iterator.
say $line; # Perl 6 filehandles autochomp, so we use say to add a newline.
РЕДАКТИРОВАТЬ : вот альтернативное решение с небольшой вспомогательной функцией, чтобы избежать необходимости явно закрывать файл.
use v6;
sub with-file($path, *&cb, *%adverbs) {
given open($path, |%adverbs) {
.&cb;
.close;
}
}
my $path = 'fileio.txt';
# Open $path for writing.
with-file $path, :w, {
.say('hello'); # Print the line "hello\n" to it.
};
# Open the file for appending.
with-file $path, :a, {
.say('world'); # Append the line "world\n" to it.
};
my $line = lines($path)[1]; # Get the second line. lines returns a lazy iterator.
say $line; # Perl 6 filehandles autochomp, so we use say to add a newline.
(без обратной связи из командной строки)
BEGIN {
print "hello" > "fileio.txt"
print "world" > "fileio.txt"
for ( i = 0; i < 2; i ++ )
getline < "fileio.txt"
fflush( "fileio.txt" );
print $0
}
import tango.text.Util, tango.io.Stdout, tango.io.device.File;
void main()
{
scope file = new File ("fileio.txt", File.ReadWriteCreate);
file.write ("hello\n");
file.write ("world\n");
auto line = splitLines (file.rewind.text())[1];
stdout(line).nl;
}
Сокращенная версия:
void main()
{
with (new File ("fileio.txt", File.ReadWriteCreate))
stdout (lineOf (put("hello\n").put("world\n").rewind.text(), 1)).nl;
}
% read_line_to_codes is defined in YAP library already.
% Uncomment the next line and remove the makeshift replacement definition to use it.
% use_module(library(readutil)).
readcodes(Stream,[]) :- peek_char(Stream,'\n'),get_char(Stream,'\n');peek_char(Stream,end_of_file).
readcodes(Stream,[First|Rest]) :- get_code(Stream,First),readcodes(Stream,Rest).
read_line_to_codes(Stream,Line) :- readcodes(Stream,Line),!.
:- open('fileio.txt',write,Stream),write(Stream,'hello\n'),close(Stream).
:- open('fileio.txt',append,Stream),write(Stream,'world'),close(Stream).
secondline(L) :- open('fileio.txt',read,Stream),read_line_to_codes(Stream,_),read_line_to_codes(Stream,L),close(Stream).
:- secondline(L),format('~s\n',[L]).
Поскольку вы хотите читать построчно, вы не можете использовать slurp, поэтому
(use 'clojure.java.io)
И затем в традиционном стиле lisp:
(let [f "hello.txt"]
(spit f "hello\n")
(spit f "world\n" :append true)
(print (second (line-seq (reader f)))))
или, лишенный любимых скобок:
(doto "hello.txt"
(spit "hello\n")
(spit "world\n" :append true)
(-> reader line-seq second print ))
Это отличается от другой версии тем, что использует print
для всего вывода и открывает файл только один раз.
with open('fileio.txt', 'w+') as f:
print('hello', file=f)
pos = f.tell()
print('world', file=f)
f.seek(pos)
s = f.read()
print(s)