Как сохранить txt файл в бд spring
Хотя с помощью ранее рассмотренных классов можно записывать текст в файлы, однако они предназначены прежде всего для работы с бинарными потоками данных, и их возможностей для полноценной работы с текстовыми файлами недостаточно. И для этой цели служат совсем другие классы, которые являются наследниками абстрактных классов Reader и Writer .
Запись файлов. Класс FileWriter
Класс FileWriter является производным от класса Writer. Он используется для записи текстовых файлов.
Чтобы создать объект FileWriter, можно использовать один из следующих конструкторов:
FileWriter(File file) FileWriter(File file, boolean append) FileWriter(FileDescriptor fd) FileWriter(String fileName) FileWriter(String fileName, boolean append)
Так, в конструктор передается либо путь к файлу в виде строки, либо объект File, который ссылается на конкретный текстовый файл. Параметр append указывает, должны ли данные дозаписываться в конец файла (если параметр равен true), либо файл должен перезаписываться.
Запишем в файл какой-нибудь текст:
import java.io.*; public class Program < public static void main(String[] args) < try(FileWriter writer = new FileWriter("notes3.txt", false)) < // запись всей строки String text = "Hello Gold!"; writer.write(text); // запись по символам writer.append('\n'); writer.append('E'); writer.flush(); >catch(IOException ex) < System.out.println(ex.getMessage()); >> >
В конструкторе использовался параметр append со значением false — то есть файл будет перезаписываться. Затем с помощью методов, определенных в базовом классе Writer производится запись данных.
Чтение файлов. Класс FileReader
Класс FileReader наследуется от абстрактного класса Reader и предоставляет функциональность для чтения текстовых файлов.
Для создания объекта FileReader мы можем использовать один из его конструкторов:
FileReader(String fileName) FileReader(File file) FileReader(FileDescriptor fd)
А используя методы, определенные в базом классе Reader, произвести чтение файла:
import java.io.*; public class Program < public static void main(String[] args) < try(FileReader reader = new FileReader("notes3.txt")) < // читаем посимвольно int c; while((c=reader.read())!=-1)< System.out.print((char)c); >> catch(IOException ex) < System.out.println(ex.getMessage()); >> >
Также мы можем считывать в промежуточный буфер из массива символов:
import java.io.*; import java.util.Arrays; public class Program < public static void main(String[] args) < try(FileReader reader = new FileReader("notes3.txt")) < char[] buf = new char[256]; int c; while((c = reader.read(buf))>0) < if(c < 256)< buf = Arrays.copyOf(buf, c); >System.out.print(buf); > > catch(IOException ex) < System.out.println(ex.getMessage()); >> >
В данном случае считываем последовательно символы из файла в массив из 256 символов, пока не дойдем до конца файла в этом случае метод read возвратит число -1.
Поскольку считанная порция файла может быть меньше 256 символов (например, в файле всего 73 символа), и если количество считанных данных меньше размера буфера (256), то выполняем копирование массива с помощью метода Arrays.copy. То есть фактически обрезаем массив buf, оставляя в нем только те символы, которые считаны из файла.
База данных в текстовом файле
Создаю простое приложение которое должно хранить данные пользователя в текстовом файле (один для всех пользователей), авторизация также должна проходить на основе этого файла. Подскажите пожалуйста как это правильно организовать? Может у кого есть пример такого решения. Библиотеки использовать нельзя, также как и xml и json.
Отслеживать
задан 22 янв 2018 в 12:24
Андрей Оробец Андрей Оробец
3 3 3 бронзовых знака
Реализуйте на коленке csv, в случае если не требуется использование экранируемых символов (т.е. приложение запрещает использование запятых и прочего) это тривиально
22 янв 2018 в 12:28
Та в java даже готовый Properties есть, который что то на вроде ini строит. Даже на коленке не надо ничего писать. mkyong.com/java/java-properties-file-examples
22 янв 2018 в 12:45
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
у меня есть пример но не знаю может быть полезно для вас или нет ! И так! Во первых создайте папку и внутри создайте FILE в формате текст это будет служить для хранилище данных.Нужно создать папку с именем model и внутри создать класс который будет хранить переменние например String name,String surname и.т.д . необходимо чтобы этот класс был implemets на Serializable в этом классе нужно ovveride-ить Getter Setter EqualsAndHashCode Constructor defaultConstructor и в этом классе всё. потом нужно создать папку с именем util внутри создать класс с иминем SerializeUtil и объявлять следующее
public static final String USER-FILE-PATH = «И ЗДЕСТЬ ДАТЬ РЕЛАТИВ ПУТЬ В ЭТОМУ ФАЙЛУ ПРИМЕР -src\mailService\data\users»; И ПОД ЭТОМУ ПИШЕМ СЛЕДУЮЩИЙ ЧТОБЫ ПОТОМ ЗВАТЬ ЭТОТ МЕТОД ЧТОБЫ КИНУТЬ USER А В ФАЙЛ
public static void serializeUser(Map userMap) throws IOException
И ПОД ЭТОМУ КОДУ ПИШЕМ СЛЕДУЮЩИЙ КОТОРЫЙ БУДЕТ ПОКАЗАТЬ ВСЕХ USER ОВ В КОНСОЛЬ потом этот метод можно звать когда хотите увидеть всех user ов но извините я забыл логику который нужно было писать и звать этот метод
public static Map deserializeUser() throws IOException, ClassNotFoundException < ObjectInputStream objectInputStream = new ObjectInputStream( new FileInputStream(USER_FILE_PATH)); return (Map) objectInputStream.readObject(); >
ТЕПЕРЬ СОЗДАЕМ ПАПКУ С ИМЕНЕМ storage И ВНУТРИ СОЗДАЕМ КЛАСС UserStorage И ВНУТРИ ПИШЕМ СЛЕДУЮЩИЙ КОД ЧТОБЫ КИНУТЬ USER А В ФАЙЛ
private Map users = new HashMap<>(); public void add(User user) < users.put(user.getEmail(), user); try < SerializeUtil.serializeUser(users); >catch (IOException e) < System.out.println(e); >>
И В ГЛАВНЫЙ КЛАСС КОТОРЫЙ Я НАЗЫВАЛ TEST НУЖНО ЗВАТЬ ЭТИ МЕТОДЫ НАПРИМЕР ЭТОТ МЕТОД ДЛЯ РЕГИСТРАЦИИ
`private static void register() < System.out.println("Please input name,surname,email,password"); String userDataStr = SCANNER.nextLine(); String[] userData = userDataStr.split(","); User user = new User(); user.setName(userData[0]); user.setSurname(userData[1]); user.setEmail(userData[2]); user.setPassword(userData[3]); USER_STORAGE.add(user); System.out.println("User was successfully added"); >>`
И когда регистрировали все данные буду падать в файл
ну и скажите от куда у меня такой странный русский язык . я не русский ))))
#4 — Запись и чтение данных из файлов (Java io)

Работа с файлами это важная часть многих языков программирования. В уроке мы научимся работать с файлами. Мы изучим добавление и чтение информации из файлов.
Видеоурок
Многие языки программирования предоставляют классы для работы с файлами и директориями проекта. Язык Java обладает множеством классов для записи и чтения данных из файлов.
Работа с файлами
При работе с файлами всегда необходимо помнить две вещи:
- Перед началом работы с файлом его необходимо открыть;
- После завершения работы с файлом его необходимо закрыть.
Если файл не открыт или же неверно открыт, то вы не можете полноценно работать с его содержимым.
С закрытием все проще, но и коварнее. Если вы не закроете файл, то программа будет работать верно, тем не менее, чем больше будет открытых файлов, тем больше программа будет перегружена и в какой-то момент она просто зависнет или выключиться.
Исключения и файлы
Поскольку не всегда известно будет ли файл в проекте или на компьютере пользователя, то всегда лучше открывать файлы за счёт использования исключений. Выполняйте открытие файлов в блоке try catch и тем самым вы обезопасите себя от любых непредвиденных обстоятельств.
Запись данных в файл
При записи данных в файл его изначально необходимо открыть. Для этого в языке Java используется класс «File»:
File file = new File("fileName.txt");
После открытия файла вы можете записать в него данные за счёт класса «PrintWriter»:
// Указываем файл для записи // В качестве объекта передаем открытый файл на основе класса File PrintWriter pw = new PrintWriter(file); // Помещаем текст внутрь файла pw.println("Working proccess");
В конце файл необходимо закрыть:
pw.close();
Чтение данных из файла
Для чтения данных файл необходимо также изначально открыть и в конце закрыть. Чтобы прочесть содержимое файла используется класс BufferedReader :
// Открываем файл для чтения // В качестве объекта передаем открытый файл на основе класса FileReader BufferedReader br = new BufferedReader(file); // Считываем данные while((String line = br.readLine()) != null) < // Выводим каждую отдельную строку в консоль System.out.println(line); >
Весь код будет доступен после подписки на проект!
Сохранение файлов в приложение и данных о них на БД

Давай представим, что ты работаешь над своим веб-приложением. В своих статьях я рассматриваю отдельные кусочки этой мозаики, как например:
- Интеграционное тестирование БД с помощью MariaDB для подмены MySql
- Реализация мультиязычности приложения
Чем эти темы полезны? А тем, что эти примеры очень близки к работе над реальными проектами, и прощупать эти темы будет ну очень полезно для тебя. Сегодня мы возьмём следующий кусочек данной мозаики — работу с файлами, так как в наше время уже и не встретить сайта, который не взаимодействует с ними (например всякие там веб-шопы, соцсети и так далее). Обзор будет проводиться на примере методов upload/download/delete , сохранять мы будем в папку (в resource) в нашем приложении, чтобы не усложнять.
Задумка состоит в том, что мы будем сохранять, помимо самого файла в наше так называемое file storage (хранилище), сущность с информацией о нашем файле (size, name и т.д.) в нашу БД — предварительно созданную таблицу. То есть при загрузке файла нам эта сущность очень даже пригодится, ну и при delete о ней нельзя никоим образом забывать. Пробежимся взглядом по этой таблице:
И давайте уже как взрослые поставим на id AUTO_INCREMENT, для автогенерирования индефикатора на уровне БД. Для начала взглянем на нашу структуру:
Сущность под продемонстрированную выше таблицу:
@Builder(toBuilder = true) @Getter @ToString public class FileInfo
Upload
Смотрим контроллер:
@RestController @RequestMapping("/file") @RequiredArgsConstructor public class FileController < private final FileService fileService; @PostMapping public ResponseEntityupload(@RequestParam MultipartFile attachment) < try < return new ResponseEntity<>(fileService.upload(attachment), HttpStatus.CREATED); > catch (IOException e) < return new ResponseEntity<>(HttpStatus.BAD_REQUEST); > >
Из интересного: 9 — Принимаем файл в виде MultipartFile . Можно принимать и в виде массива байтов, но этот вариант мне нравится больше, так как мы с MultipartFile можем вытягивать различные свойства переданного файла. 10 — 14 — оборачиваем наши действия в try catch , чтобы если на более низком уровне возникнет исключение, мы его пробросили выше и отправили 400 ошибку ответом. Далее — уровень сервиса:
public interface FileService < FileInfo upload(MultipartFile resource) throws IOException;
Смотрим реализацию:
@Service @RequiredArgsConstructor public class FileServiceImpl implements FileService < private final FileDAO fileDAO; private final FileManager fileManager; @Transactional(rollbackFor = ) @Override public FileInfo upload(MultipartFile resource) throws IOException
8 — в случае падения IOException, все наши сохранения в БД откатятся. 11 — генерируем ключ, который будет уникальным для файла, когда он будет соохранен (даже если будут сейвиться два файла с одинаковыми именами, путаницы не возникнет). 12 — строим сущность для сохранения в БД. 17 — загоняем сущность с инфой в БД. 18 — сохраняем файл с за хешированным именем. 20 — возвращаем созданую сущность FileInfo , но со сгенерированным id в БД (об этом речь пойдёт чуть ниже) и датой создания. Метод генерации ключа к файлу:
private String generateKey(String name)
Здесь мы хешируем имя + дата создания, что и обеспечит нам уникальность. Интерфейс dao слоя:
public interface FileDAO < FileInfo create(FileInfo file);
Его имплементация:
@Repository @RequiredArgsConstructor public class FileDAOImpl implements FileDAO < private static final String CREATE_FILE = "INSERT INTO files_info(file_name, file_size, file_key, upload_date) VALUES (?, ?, ?, ?)"; private final JdbcTemplate jdbcTemplate; @Override public FileInfo create(final FileInfo file) < LocalDate uploadDate = LocalDate.now(); GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(x ->< PreparedStatement preparedStatement = x.prepareStatement(CREATE_FILE, Statement.RETURN_GENERATED_KEYS); preparedStatement.setString(1, file.getName()); preparedStatement.setLong(2, file.getSize()); preparedStatement.setString(3, file.getKey()); preparedStatement.setDate(4, Date.valueOf(uploadDate)); return preparedStatement; >, keyHolder); return file.toBuilder() .id(keyHolder.getKey().longValue()) .uploadDate(uploadDate) .build(); >
11 — создаём дату которую и сохраним. 12 - 21 — сохраняем сущность, но более сложным путем, с явным созданием объекта PreparedStatement , чтобы можно было вытащить сгенерированный id (он его вытягивает не отдельным запросом, а в виде ответных метаданных). 22 - 26 — достраиваем нашу многострадальную сущность и отдаем наверх (на самом деле он его не достраивает, а создаёт новый объект, заполняя переданные поля и копируя остальные с изначального). Давайте посмотрим, как будут сохраняться наши файлы в FileManager :
public void upload(byte[] resource, String keyName) throws IOException < Path path = Paths.get(DIRECTORY_PATH, keyName); Path file = Files.createFile(path); FileOutputStream stream = null; try < stream = new FileOutputStream(file.toString()); stream.write(resource); >finally < stream.close(); >>

1 — принимаем файл в виде массива байтов и отдельно имя, под которым он будет сохранен (наш сгенерированный ключ). 2 - 3 — создаем путь (а в пути прописываем путь плюс наш ключ) и файл по нему. 6 - 7 — создаем поток и пишем туда наши байты (и оборачиваем это все добро в try-finally чтобы быть уверенными, что поток точно закроется). Тем не менее, многие из методов могут нам выкинуть IOException. В таком случае, благодаря прописанной в шапке метода проброске, мы прокинем его в контроллер и отдадим 400 статус. Давайте протестируем все это дело в Postman: Как видим, все отлично, ответ 201, ответный JSON пришел в виде нашей сохраняемой сущности в БД, и если заглянем в наше хранилище: БД: увидим, что у нас появилось новое значение. (=*;*=)
Download
Controller:
@GetMapping(path = "/", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public ResponseEntity download(@PathVariable("id") Long id) < try < FileInfo foundFile = fileService.findById(id); Resource resource = fileService.download(foundFile.getKey()); return ResponseEntity.ok() .header("Content-Disposition", "attachment; filename lang-java line-numbers"> Resource download(String key) throws IOException; FileInfo findById(Long fileId);
Реализация:
@Override public Resource download(String key) throws IOException < return fileManager.download(key); >@Transactional(readOnly = true) @Override public FileInfo findById(Long fileId)
Тут особо интересного ничего нет: метод поиска сущности по id и загрузка файла, разве что 46 — помечаем, что транзакция у нас для чтения. Уровень dao:
FileInfo findById(Long fileId);
Имплементация:
private static final String FIND_FILE_BY_ID = "SELECT id, file_name, file_size, file_key, upload_date FROM files_info WHERE FileInfo findById(Long fileId) < return jdbcTemplate.queryForObject(FIND_FILE_BY_ID, rowMapper(), fileId); >private RowMapper rowMapper() < return (rs, rowNum) ->FileInfo.builder() .id(rs.getLong("id")) .name(rs.getString("file_name")) .size(rs.getLong("file_size")) .key(rs.getString("file_key")) .uploadDate(rs.getObject("upload_date", LocalDate.class)) .build(); >
4 — поиск по id c использованием jdbcTemplate и RowMapper . 8 - 15 — реализация RowMapper для нашего конкретного случая, для сопоставления данных из БД и полей модели. Идем в FileManager и смотрим, как загружается наш файл:
public Resource download(String key) throws IOException < Path path = Paths.get(DIRECTORY_PATH + key); Resource resource = new UrlResource(path.toUri()); if (resource.exists() || resource.isReadable()) < return resource; >else < throw new IOException(); >>

Возвращаем файл в виде объекта Resource , а искать будем по ключу. 3 — создаем Resource по пути + ключ. 4 - 8 — проверяем, что файл по заданному пути не пуст и читаем. Если всё ОК, возвращаем его, а если нет, прокидываем IOException наверх. Проверяем наш метод в Postman: Как видим, он отработал на ОК))
Delete
@DeleteMapping(value = "/") public ResponseEntity delete(@PathVariable("id") Long id) < try < fileService.delete(id); return new ResponseEntity<>(HttpStatus.OK); > catch (IOException e) < return new ResponseEntity<>(HttpStatus.NOT_FOUND); > >
Тут ничего особенного: также возвращаем 404 в случае неудачи с помощью try-catch . Интерфейс сервиса:
void delete(Long fileId) throws IOException;
Implementation:
@Transactional(rollbackFor = ) @Override public void delete(Long fileId) throws IOException
1 — также откат изменения данных (удаления) при падении IOException. 5 — удаляем информацию о файле из БД. 6 — удаляем сам файл из нашего “хранилища”. Интерфейс dao:
void delete(Long fileId);
Реализация:
private static final String DELETE_FILE_BY_ID = "DELETE FROM files_info WHERE void delete(Long fileId)
Ничего такого — просто delete. Удаление самого файла:
public void delete(String key) throws IOException < Path path = Paths.get(DIRECTORY_PATH + key); Files.delete(path); >>
Юзаем в Postman:
Смотрим в хранилище:
Пусто 🙂 Теперь в БД:
Видим, что все good))
Test
Давайте попробуем написать тест под наш FileManager . Для начала взглянем на структуру тестовой части: mockFile.txt — это файл, с помощью которого мы будем тестить наши операции с file storage. testFileStorage будет заменой нашего хранилища. FileManagerTest :
public class FileManagerTest < private static MultipartFile multipartFile; private static FileManager manager; private static FileInfo file; @BeforeClass public static void prepareTestData() throws IOException < file = FileInfo.builder() .id(9L) .name("mockFile.txt") .key("mockFile.txt") .size(38975L) .uploadDate(LocalDate.now()) .build(); multipartFile = new MockMultipartFile("mockFile", "mockFile.txt", "txt", new FileInputStream("src/test/resources/mockFile.txt")); manager = new FileManager(); >
Здесь мы видим задание тестовых данных. Тест сохранения файла:
@Test public void uploadTest() throws IOException < ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/testFileStorage/"); manager.upload(multipartFile.getBytes(), "mockFile.txt"); Path checkFile = Paths.get("src/test/resources/testFileStorage/mockFile.txt"); assertThat(Files.exists(checkFile)).isTrue(); assertThat(Files.isRegularFile(checkFile)).isTrue(); assertThat(Files.size(checkFile)).isEqualTo(multipartFile.getSize()); Files.delete(checkFile); >
3 — с помощью тестовой рефлексии меняем нашу константу в сервисе для задания пути сохранения файла. 5 — вызываем проверяемый метод. 7 - 10 — проверяем правильность исполнения сохранения. 11 — удаляем сохраненный файл (мы не должны оставить никаких следов).
@Test public void downloadTest() throws IOException < ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/"); Resource resource = manager.download(file.getKey()); assertThat(resource.isFile()).isTrue(); assertThat(resource.getFilename()).isEqualTo(file.getName()); assertThat(resource.exists()).isTrue(); >
Тест загрузки файла: 3 — опять же, меняем путь для нашего FileManager . 5 — юзаем проверяемый метод. 7 - 9 — проверяем результат исполнения. Тест удаления файла:
@Test public void deleteTest() throws IOException < Path checkFile = Paths.get("src/test/resources/testFileStorage/mockFile.txt"); Files.createFile(checkFile); assertThat(Files.exists(checkFile)).isTrue(); assertThat(Files.isRegularFile(checkFile)).isTrue(); ReflectionTestUtils.setField(manager, "DIRECTORY_PATH", "src/test/resources/testFileStorage/"); manager.delete(file.getKey()); assertThat(Files.notExists(checkFile)).isTrue(); >
9 - 3 - 4 — задаем путь и создаем файл. 5 - 6 — проверяем его существование. 9 — используем проверяемый метод. 77 — проверяем, что обьекта уже нет. И смотрим, что там у нас по зависимостям:
org.springframework.boot spring-boot-starter-data-jdbc org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine org.projectlombok lombok 1.18.10 provided mysql mysql-connector-java 8.0.18 commons-codec commons-codec 1.9 junit junit 4.13-rc-2 test