. (utf8) 2:- module( 3 file_ext, 4 [ 5 append_directories/2, % +Directories, -Directory 6 cat/2, % +Out, +Files 7 change_file_name_extension/3, % ?FromFile, ?FromExtension, ?ToFile 8 change_file_name_extension/4, % ?FromFile, ?FromExtension, ?ToExtension, ?ToFile 9 change_file_name_extensions/3, % ?FromFile, ?FromExtensions, ?ToFile 10 change_file_name_extensions/4, % ?FromFile, ?FromExtensions, ?ToExtensions, ?ToFile 11 compress_file/1, % +FromFile 12 compress_file/2, % +FromFile, ?ToFile 13 concatenate_files/2, % +Files, +ConcatenatedFile 14 convert_file/2, % +File, +Format 15 convert_file/3, % +FromFile, +Format, ?ToFile 16 create_directory/1, % +Directory 17 create_file_directory/1, % +File 18 decompress_file/2, % +FromFile, +ToFile 19 delete_files_by_extension/1, % +Extension 20 delete_files_by_extension/2, % +Directory, +Extension 21 delete_files_by_extensions/1, % +Extensions 22 delete_files_by_extensions/2, % +Directory, +Extensions 23 directory_file/2, % +Directory, -File 24 directory_file_path2/3, % ?Directory, ?File, ?Path 25 directory_parent/2, % +ChildDirectory, -ParentDirectory 26 directory_path/2, % ?Directory, ?Path 27 directory_path_recursive/2, % +Directory, -Path 28 directory_subdirectories/2, % ?Directory, ?Subdirectories 29 directory_subdirectory/2, % +Directory, ?Subdirectory 30 directory_subdirectory/3, % +Directory, ?Local, ?Subdirectory 31 file_call/2, % +File, Goal_1 32 file_extension/2, % +File, -Extension 33 file_extensions/2, % +File, -Extensions 34 file_extensions_media_type/2, % +Extensions, -MediaType 35 file_is_fresh/2, % +File, +LastModified 36 file_line/2, % +File, -Line 37 file_media_type/2, % +File, -MediaType 38 file_mode/2, % +File, +Mode 39 file_name/2, % ?File, ?Name 40 file_name_extension2/3, % ?File, ?Name, ?Extension 41 file_name_extensions/3, % ?File, ?Name, ?Extensions 42 file_size/2, % +File, -Size 43 file_to_string/2, % +File, -String 44 guess_file_encoding/2, % +File, ?Encoding 45 home_directory/1, % ?Directory 46 is_dummy_file/1, % +File 47 is_empty_directory/1, % +Directory 48 is_empty_file/1, % +File 49 peek_file/3, % +File, +Size, -String 50 read_from_file/2, % +File, :Goal_1 51 read_from_file/3, % +File, :Goal_1, +Options 52 read_write_file/2, % +FromFile, :Goal_2 53 read_write_file/3, % +FromFile, :Goal_2, +Options 54 read_write_file/4, % +FromFile, :Goal_2, +ReadOptions, +WriteOptions 55 read_write_files/3, % +FromFile, +ToFile, :Goal_2 56 read_write_files/4, % +FromFile, +ToFile, :Goal_2, +Options 57 read_write_files/5, % +FromFile, +ToFile, :Goal_2, +ReadOptions, +WriteOptions 58 recode_file/1, % +File 59 recode_file/2, % +File, +FromEncoding 60 recode_files/2, % +FromFile, +ToFile 61 recode_files/3, % +FromFile, +FromEncoding, +ToFile 62 sort_file/1, % +File 63 sort_file/2, % +File, +Options 64 touch/1, % +File 65 working_directory/1, % -Directory 66 write_to_file/2, % +File, :Goal_1 67 write_to_file/3 % +File, :Goal_1, +Options 68 ] 69). 70:- reexport(library(filesex)). 71:- reexport(library(stream_ext)).
77:- use_module(library(apply)). 78:- use_module(library(error)). 79:- use_module(library(lists)). 80:- use_module(library(readutil)). 81:- use_module(library(yall)). 82:- use_module(library(zlib)). 83 84:- use_module(library(call_ext)). 85:- use_module(library(dict)). 86:- use_module(library(hash_ext)). 87:- use_module(library(media_type)). 88:- use_module(library(sort_ext)). 89:- use_module(library(stream_ext)). 90:- use_module(library(thread_ext)). 91 92:- meta_predicate 93 call_file_( , , , ), 94 call_files_( , , , , , , ), 95 file_call( , ), 96 read_from_file( , ), 97 read_from_file( , , ), 98 read_write_file( , ), 99 read_write_file( , , ), 100 read_write_file( , , , ), 101 read_write_files( , , ), 102 read_write_files( , , , ), 103 read_write_files( , , , , ), 104 write_to_file( , ), 105 write_to_file( , , ). 106 107:- multifile 108 error:has_type/2. 109 110errorhas_type(directory, Directory) :- 111 var(Directory), !, 112 instantiation_error(Directory). 113errorhas_type(directory, Directory) :- 114 \+ exists_directory(Directory), !, 115 existence_error(directory, Directory). 116errorhas_type(directory, Directory) :- 117 error:has_type(atom, Directory). 118errorhas_type(media_type, media(Supertype/Subtype,Parameters)) :- 119 maplist(error:has_type(atom), [Supertype,Subtype]), 120 error:has_type(list(compound), Parameters).
128append_directories([], '/') :- !. 129append_directories([H], H) :- !. 130append_directories([H|T], Dir) :- 131 append_directories_(H, T, Dir). 132 133append_directories_(Dir, [], Dir) :- !. 134append_directories_(Dir1, [H|T], Dir3) :- 135 append_directories(Dir1, H, Dir2), 136 append_directories_(Dir2, T, Dir3).
The empty atom in the first position indicates the root directory.
Does not ensure that any of the directories exist.
148append_directories(Dir1, Dir2, Dir3) :- 149 directory_subdirectories(Dir1, Subdirs1), 150 directory_subdirectories(Dir2, Subdirs2a), 151 remove_root_(Subdirs2a, Subdirs2b), 152 append(Subdirs1, Subdirs2b, Subdirs3), 153 directory_subdirectories(Dir3, Subdirs3). 154 155remove_root_([''|T], T) :- !. 156remove_root_(L, L).
162cat(Out, Files) :- 163 maplist(cat_file(Out), Files). 164 165cat_file(Out, File) :- 166 read_from_file(File, {Out}/[In0]>>copy_stream_data(In0, Out)).
172change_file_name_extension(FromFile, ToExt, ToFile) :-
173 change_file_name_extension(FromFile, _, ToExt, ToFile).
181change_file_name_extension(FromFile, FromExt, ToExt, ToFile) :-
182 file_name_extension(Base, FromExt, FromFile),
183 file_name_extension(Base, ToExt, ToFile).
189change_file_name_extensions(FromFile, ToExt, ToFile) :-
190 change_file_name_extensions(FromFile, _, ToExt, ToFile).
198change_file_name_extensions(FromFile, FromExt, ToExt, ToFile) :-
199 file_name_extensions(Base, FromExt, FromFile),
200 file_name_extensions(Base, ToExt, ToFile).
208compress_file(FromFile) :- 209 compress_file(FromFile, _). 210 211 212compress_file(FromFile, ToFile) :- 213 (var(ToFile) -> file_name_extension(FromFile, gz, ToFile) ; true), 214 read_write_files(FromFile, ToFile, copy_stream_data).
220concatenate_files(Files, File) :- 221 setup_call_cleanup( 222 open(File, write, Out), 223 concatenate_files0(Files, Out), 224 close(Out) 225 ). 226 227concatenate_files0([], _) :- !. 228concatenate_files0([H|T], Out) :- !, 229 setup_call_cleanup( 230 open(H, read, In), 231 copy_stream_data(In, Out), 232 close(In) 233 ), 234 concatenate_files0(T, Out).
247convert_file(File, Format) :- 248 convert_file(File, Format, _). 249 250 251convert_file(FromFile, Format, ToFile) :- 252 call_must_be(convert_format, Format), 253 from_to_file_(FromFile, [Format], ToFile), 254 file_directory_name(ToFile, ToDir), 255 process_create( 256 path(libreoffice), 257 ['--convert-to',Format,'--infilter=CSV:44,34,76,1','--outdir',ToDir,file(FromFile)], 258 [] 259 ). 260 261convert_format(csv).
267create_directory(Dir) :- 268 exists_directory(Dir), !. 269create_directory(Dir) :- 270 make_directory_path(Dir).
278create_file_directory(Path) :-
279 (exists_directory(Path) -> Dir = Path ; directory_file_path(Dir, _, Path)),
280 create_directory(Dir).
286decompress_file(FromFile, ToFile) :-
287 read_write_files(FromFile, ToFile, copy_stream_data).
294delete_files_by_extension(Ext) :- 295 working_directory(Dir), 296 delete_files_by_extension(Dir, Ext). 297 298 299delete_files_by_extension(Dir, Ext) :- 300 format(atom(Wildcard1), "*.~a", [Ext]), 301 directory_file_path(Dir, Wildcard1, Wildcard2), 302 expand_file_name(Wildcard2, Files), 303 maplist(delete_file, Files).
310delete_files_by_extensions(Exts) :- 311 working_directory(Dir), 312 delete_files_by_extensions(Dir, Exts). 313 314 315delete_files_by_extensions(Dir, Exts) :- 316 threaded_maplist_1(delete_files_by_extension(Dir), Exts). 317 318 319 320% directory_file(+Directory:atom, -File:atom) is nondet. 321% 322% Non-deterministic variant of directory_files/2 that skips dummy 323% files. 324 325directory_file(Dir, File) :- 326 directory_files(Dir, Files), 327 member(File, Files), 328 \+ is_dummy_file(File).
339directory_file_path2(Dir, File, Path) :- 340 ground(Dir), var(File), var(Path), !, 341 directory_file(Dir, File), 342 directory_file_path(Dir, File, Path). 343directory_file_path2(Dir, File, Path) :- 344 directory_file_path(Dir, File, Path).
350directory_parent(Dir1, Dir2) :-
351 directory_subdirectories(Dir1, Subdirs1),
352 once(append(Subdirs2, [_], Subdirs1)),
353 directory_subdirectories(Dir2, Subdirs2).
360directory_path(Dir, Path) :-
361 directory_file(Dir, File),
362 directory_file_path(Dir, File, Path).
368directory_path_recursive(Dir, Path) :-
369 directory_path(Dir, Path0),
370 ( exists_directory(Path0)
371 -> directory_path_recursive(Path0, Path)
372 ; Path = Path0
373 ).
and
.. in
Directory' are resolved.
The empty atom in the first position indicates the root directory.
For absolute directory names the first subdirectory name is the empty atom.
387directory_subdirectories(Dir, Subdirs2) :- 388 ground(Dir), !, 389 atomic_list_concat(Subdirs1, /, Dir), 390 resolve_subdirectories(Subdirs1, Subdirs2). 391directory_subdirectories(Dir, Subdirs1) :- 392 resolve_subdirectories(Subdirs1, Subdirs2), 393 atomic_list_concat(Subdirs2, /, Dir).
400directory_subdirectory(Dir, Subdir) :-
401 directory_subdirectory(Dir, _, Subdir).
408directory_subdirectory(Dir, Local, Subdir) :- 409 ground(Local), !, 410 directory_file_path(Dir, Local, Subdir), 411 exists_directory(Subdir). 412directory_subdirectory(Dir, Local, Subdir) :- 413 directory_path(Dir, Subdir), 414 exists_directory(Subdir), 415 directory_file_path(_, Local, Subdir).
421file_call(File, Goal_1) :-
422 setup_call_cleanup(
423 open(File, read, In),
424 call(Goal_1, In),
425 close(In)
426 ).
432file_extension(File, Ext) :-
433 file_extensions(File, Exts),
434 member(Ext, Exts).
440file_extensions(File, Exts) :-
441 file_name_extensions(File, _, Exts).
447file_extensions_media_type(Exts, MediaType) :-
448 member(Ext, Exts),
449 media_type_extension(MediaType, Ext), !.
455file_is_fresh(File, LMod) :-
456 exists_file(File),
457 \+ is_empty_file(File),
458 time_file(File, Sync),
459 Sync > LMod.
465file_line(File, Line) :-
466 read_from_file(File, {Line}/[In0]>>stream_line(In0, Line)).
472file_media_type(File, MediaType) :-
473 file_extension(File, Ext),
474 media_type_extension(MediaType, Ext).
483file_mode(File, Mode) :-
484 ( exists_file(File)
485 -> ( access_file(File, Mode)
486 -> true
487 ; permission_error(Mode, file, File)
488 )
489 ; existence_error(file, File)
490 ).
497file_name(File, Name) :-
498 file_name_extensions(File, Name, _).
505file_name_extension2(File, Name, Ext) :-
506 file_name_extensions(File, Name, [Ext]).
513file_name_extensions(File, Name, Exts) :- 514 ground(File), !, 515 directory_file_path2(Dir, Local, File), 516 atomic_list_concat([Base|Exts], ., Local), 517 directory_file_path2(Dir, Base, Name). 518file_name_extensions(File, Name, Exts) :- 519 atomic_list_concat([Name|Exts], ., File).
527file_size(File, Size) :-
528 size_file(File, Size).
534file_to_string(File, String) :-
535 read_file_to_string(File, Codes, []),
536 string_codes(String, Codes).
548guess_file_encoding(File, Enc1) :-
549 read_from_file(
550 File,
551 {Enc2}/[In0]>>guess_encoding(In0, Enc2),
552 options{type: binary}
553 ),
554 ( var(Enc1)
555 -> Enc1 = Enc2
556 ; stream_ext:clean_encoding_(Enc1, Enc3),
557 Enc3 == Enc2
558 -> true
559 ; throw(error(unexpected_encoding(Enc2,Enc1),guess_file_encoding/2))
560 ).
567home_directory(Dir) :-
568 expand_file_name(~, [Dir]).
574is_dummy_file(.). 575is_dummy_file(..).
581is_empty_directory(Dir) :-
582 exists_directory(Dir),
583 \+ directory_file(Dir, _).
589is_empty_file(File) :-
590 read_from_file(File, at_end_of_stream).
596peek_file(File, Size, Str) :-
597 read_from_file(File, {Size,Str}/[In0]>>peek_string(In0, Size, Str)).
607read_from_file(File, Goal_1) :- 608 read_from_file(File, Goal_1, options{}). 609 610 611read_from_file(File, Goal_1, Options) :- 612 call_file_(File, read, Goal_1, Options).
619read_write_file(File, Goal_2) :- 620 read_write_file(File, Goal_2, options{}). 621 622 623read_write_file(File, Goal_2, Options) :- 624 read_write_file(File, Goal_2, Options, Options). 625 626 627read_write_file(File, Goal_2, ReadOptions, WriteOptions) :- 628 file_name_extensions(File, Base, FromExts), 629 ( append(Exts, [gz], FromExts) 630 -> append(Exts, [tmp,gz], TmpExts), 631 file_name_extensions(TmpFile, Base, TmpExts) 632 ; file_name_extension(File, tmp, TmpFile) 633 ), 634 read_write_files(File, TmpFile, Goal_2, ReadOptions, WriteOptions), 635 rename_file(TmpFile, File).
643read_write_files(FromFile, ToFile, Goal_2) :- 644 read_write_files(FromFile, ToFile, Goal_2, options{}). 645 646 647read_write_files(FromFile, ToFile, Goal_2, Options) :- 648 read_write_files(FromFile, ToFile, Goal_2, Options, Options). 649 650 651read_write_files(FromFile, ToFile, Goal_2, ReadOptions, WriteOptions) :- 652 create_file_directory(ToFile), 653 call_files_(FromFile, read, ToFile, write, Goal_2, ReadOptions, WriteOptions).
662recode_file(File) :- 663 guess_file_encoding(File, Enc), 664 recode_file(File, Enc). 665 666 667% Optimization: do not copy stream contents when the encoding remains 668% the same. 669recode_file(_, utf8) :- !. 670recode_file(File, Enc) :- 671 read_write_file( 672 File, 673 {Enc}/[In,Out0]>>recode_stream(In, Enc, Out0), 674 options{type: binary} 675 ).
682recode_files(FromFile, ToFile) :- 683 guess_file_encoding(FromFile, Enc), 684 recode_files(FromFile, Enc, ToFile). 685 686 687recode_files(FromFile, Enc1, ToFile) :- 688 stream_ext:clean_encoding_(Enc1, Enc2), 689 ( % Optimization: do not copy stream contents when the encoding 690 % remains the same. 691 Enc2 == utf8 692 -> true 693 ; read_write_files( 694 FromFile, 695 ToFile, 696 {Enc2}/[In0,Out0]>>recode_stream(In0, Enc2, Out0), 697 options{type: binary} 698 ) 699 ).
707resolve_subdirectories([], []) :- !. 708resolve_subdirectories([''], []) :- !. 709resolve_subdirectories([.|T1], T2) :- !, 710 resolve_subdirectories(T1, T2). 711resolve_subdirectories([_,..|T1], T2) :- !, 712 resolve_subdirectories(T1, T2). 713resolve_subdirectories([H|T1], [H|T2]) :- 714 resolve_subdirectories(T1, T2).
721sort_file(File) :- 722 sort_file(File, options{}). 723 724 725sort_file(File, Options) :- 726 read_write_file( 727 File, 728 {Options}/[In0,Out0]>>( 729 sort_stream(In0, ProcOut, Options), 730 call_cleanup( 731 copy_stream_data(ProcOut, Out0), 732 close(ProcOut) 733 ) 734 ) 735 ).
741touch(File) :-
742 setup_call_cleanup(
743 open(File, write, Out),
744 true,
745 close(Out)
746 ).
752working_directory(Directory) :-
753 working_directory(Directory, Directory).
762write_to_file(File, Goal_1) :- 763 write_to_file(File, Goal_1, options{}). 764 765 766write_to_file(File, Goal_1, Options) :- 767 create_file_directory(File), 768 call_file_(File, write, Goal_1, Options). 769 770 771 772 773 774% GENERICS %
787call_file_(File, DefaultMode, Goal_1, Options) :-
788 dict_get(mode, Options, DefaultMode, Mode),
789 setup_call_cleanup(
790 open_file_(File, Mode, Stream, Options),
791 call(Goal_1, Stream),
792 close(Stream)
793 ).
805call_files_(File1, Mode1, File2, Mode2, Goal_2, Options1, Options2) :-
806 setup_call_cleanup(
807 maplist(
808 open_file_,
809 [File1,File2],
810 [Mode1,Mode2],
811 [Stream1,Stream2],
812 [Options1,Options2]
813 ),
814 call(Goal_2, Stream1, Stream2),
815 maplist(close, [Stream1,Stream2])
816 ).
823from_to_file_(FromFile, Exts, ToFile) :- 824 var(ToFile), !, 825 directory_file_path2(Dir, FromBase, FromFile), 826 file_name(FromBase, Local), 827 file_name_extensions(ToBase, Local, Exts), 828 directory_file_path2(Dir, ToBase, ToFile). 829from_to_file_(_, _, _).
838open_file_(File, Mode, Stream2, Options) :-
839 access_file(File, Mode),
840 open_gz_(File, Mode, Stream1, Options),
841 open_hash_(Stream1, Stream2, Options).
854% explicitly no compression 855open_gz_(File, Mode, Stream, Options) :- 856 options{compression: none} :< Options, !, 857 open(File, Mode, Stream, Options). 858% compression (GNU zip) 859open_gz_(File, Mode, Stream, Options) :- 860 ( options{compression: gzip} :< Options 861 ; file_name_extension(_, gz, File) 862 ), !, 863 dict_terms(Options, SwiOptions), 864 gzopen(File, Mode, Stream, SwiOptions). 865% implicitly no compression 866open_gz_(File, Mode, Stream, Options) :- 867 dict_terms(Options, SwiOptions), 868 open(File, Mode, Stream, SwiOptions).
874open_hash_(Stream1, Stream2, Options) :- 875 hash_algorithm_(Options, Algorithm), !, 876 open_hash_stream(Stream1, Stream2, [algorithm(Algorithm),close_parent(false)]). 877open_hash_(Stream, Stream, _). 878 879hash_algorithm_(Options, Algorithm) :- 880 hash_algorithm(Algorithm), 881 dict_key(Options, Algorithm)
Additional support for working with files
*/