Skip to content

50 file managment system #72

Merged
merged 16 commits into from
Apr 8, 2026
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .idea/checkstyle-idea.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

81 changes: 81 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileConverter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
* Converts stock objects to/from string format for file handling.
*
* <p style ="font-weight: bold;">Responsibilities:</p>
* <ul>
* <li>Turn a valid list of stock string elements to a
* list of {@link Stock} objects.</li>
*
* <li>Turn a list of stock objects to a
* list of string elements.</li>
* </ul>
*
* <p>Used with {@link FileParser}</p>
*
* @see FileParser
* @author tohja
* @version 1.0.0
* */
public class FileConverter {

/**
* Turns a list of valid string representations
* of stock objects to a list of stock objects.
*
* @param validStocks list of string elements properly
* representing stock objects.
*
* @return {@link List<Stock>}
*
* @throws IllegalArgumentException if stock object(s) cannot be converted.
*
* */
public List<Stock> getStocksFromStrings(final List<String> validStocks) {

List<Stock> stocksFromFile = new ArrayList<>();
List<String> stockSymbols = new ArrayList<>();

validStocks.forEach(s -> {
String[] lineElements = s.split(",");
String stockSymbol = lineElements[0].trim();
String stockName = lineElements[1].trim();
BigDecimal stockPrice = new BigDecimal(lineElements[2].trim());

try {
Stock stockObject = new Stock(stockSymbol, stockName, stockPrice);
if (!stockSymbols.contains(stockSymbol)) {
stockSymbols.add(stockSymbol);
stocksFromFile.add(stockObject);
}
} catch (IllegalArgumentException e) {
System.err.println("(" + s + ") is not a valid stock! Skipping...");
}

});
return stocksFromFile;
}

/**
* Converts a list of stocks to string representations of that stock.
*
* <p>format: SYMBOL, NAME, PRICE</p>
*
* @param stocks a list of {@link Stock} objects.
*
* @return a list of string representation of the stock objects.
* */
public List<String> stocksToStrings(final List<Stock> stocks) {
ArrayList<String> stringList = new ArrayList<>();
stocks.forEach(s ->
stringList.add(s.getSymbol().trim() + "," + s.getCompany().trim()
+ "," + s.getSalesPrice().toString())
);
return stringList;
}
}
184 changes: 184 additions & 0 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/FileParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.function.Predicate;

/**
* Class used to parse (filter) valid stocks from a .txt file.
*
* <p style ="font-weight: bold;">Responsibilities:</p>
* <ul>
* <li>Read file and return a filtered list of string elements,
* where each element represents a valid stock line.</li>
*
* <li>Write a list of string representations of stock objects
* to file, each stock separated by a line.</li>
* </ul>
*
* <p>Used with {@link FileConverter}</p>
*
* @see FileConverter
* @author tohja
* @version 1.0.0
* */
public class FileParser {

/** The path name this parser is using.*/
private final String pathName;

/**
* Rule set for validating lines and strings.
*
* <p>Uses predicates.</p>
* */
private enum ParserRuleSet {

/**
* Rule for whether string is empty or not.
* */
NOT_EMPTY(s -> !s.trim().isEmpty()),

/**
* Rule for if string is comment or not.
* */
NOT_COMMENT(s -> !s.startsWith("#")),

/**
* Rule for if line is in valid format.
* */
VALID_FORMAT(NOT_EMPTY.rule.and(NOT_COMMENT.rule)),

/**
* Rule for if string is considered a valid company symbol.
* */
VALID_CODE(s -> s.matches("[A-Z]{4}")),

/**
* Rule for if string is a valid company name.
* */
VALID_NAME(s -> s.matches(".*")),

/**
* Rule for if string can be parsed to a {@link BigDecimal} object.
* */
CAN_PARSE_TO_BIG_DECIMAL(s -> {
try {
new BigDecimal(s);
return true;
} catch (NumberFormatException e) {
return false;
}
}),

/**
* Rule for if string is in a valid price format.
* */
VALID_PRICE_FORMAT(s -> s.matches("[^a-zA-Z]+")),

/**
* Rule for if string is a valid price.
* */
VALID_PRICE(VALID_PRICE_FORMAT.rule.and(CAN_PARSE_TO_BIG_DECIMAL.rule));

/**
* The constants' rules as predicates with input of type string.
* */
private final Predicate<String> rule;

ParserRuleSet(final Predicate<String> rule) {
this.rule = rule;
}
}

/**
* Constructor.
*
* @param pathName the file path name to read.
* */
public FileParser(final String pathName) {
this.pathName = pathName;
}

/**
* Reads the file and returns a list element of all valid stocks as strings.
*
* <p>Uses {@link BufferedReader} for opening a file stream. </p>
*
* @return {@link List<String>} object of all valid stock strings in file.
*
* @throws IOException if path cannot be read.
*
* @see Path
* */

public List<String> readFile() throws IOException {
Path path = Paths.get(pathName);
try (BufferedReader bufferedReader = Files.newBufferedReader(path)) {

List<String> allLines = bufferedReader.readAllLines();
List<String> readableLines =
allLines.stream()
.filter(ParserRuleSet.VALID_FORMAT.rule).toList();

// Valid lines (following the correct regular expressions)
return readableLines.stream().filter(s -> {
String[] parts = s.trim().split(",");

if (parts.length != 3) {
return false;
}

boolean validCode = ParserRuleSet
.VALID_CODE.rule.test(parts[0].trim());

boolean validName = ParserRuleSet
.VALID_NAME.rule.test(parts[1].trim());

boolean validPrice = ParserRuleSet
.VALID_PRICE.rule.test(parts[2].trim());

return validCode && validName && validPrice;
}).toList();

} catch (IOException e) {
throw new IOException("File parser could not parse file!");
}
}

/**
* Writes a given lists of stocks to the file.
*
* <p>Uses {@link BufferedWriter}.</p>
*
* @param stringList list of strings representing stocks in the format
* SYMBOL, NAME, PRICE
*
* @throws IOException if writing process throws error.
* */
public void writeStocksToFile(final List<String> stringList)
throws IOException {
Path path = Paths.get(pathName);

try (BufferedWriter writer = Files.newBufferedWriter(path,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND)) {

writer.newLine();

for (String line : stringList) {
writer.write(line);
writer.newLine();
}
} catch (IOException e) {
throw new IOException("Error during buffered write", e);
}
}
}
21 changes: 11 additions & 10 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
import java.io.IOException;
import java.util.List;

public class Main {
static void main() {
//TIP Press <shortcut actionId="ShowIntentionActions"/> with your caret at the highlighted text
// to see how IntelliJ IDEA suggests fixing it.
IO.println(String.format("Hello and welcome!"));

for (int i = 1; i <= 5; i++) {
//TIP Press <shortcut actionId="Debug"/> to start debugging your code. We have set one <icon src="AllIcons.Debugger.Db_set_breakpoint"/> breakpoint
// for you, but you can always add more by pressing <shortcut actionId="ToggleLineBreakpoint"/>.
IO.println("i = " + i);
FileParser parser1 = new FileParser("src/main/resources/dummydata.txt");
FileConverter converter1 = new FileConverter();
try {
List<Stock> stocksInFile = converter1.getStocksFromStrings(parser1.readFile());
parser1.writeStocksToFile(converter1.stocksToStrings(stocksInFile));
stocksInFile.forEach(s -> System.out.println(s.getSymbol()));
} catch (IOException e) {
System.err.println(e.getMessage());
}
}
}
4 changes: 2 additions & 2 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Stock.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package edu.ntnu.idi.idatt2003.g40.mappe;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
Expand Down Expand Up @@ -50,7 +51,7 @@ public Stock(final String symbol,
*
* @return the stock symbol
*/
public String getSymbol() {
public String getSymbol() {
return symbol;
}

Expand Down Expand Up @@ -129,5 +130,4 @@ public BigDecimal getLatestPriceChange() {

return currentPrice.subtract(previousPrice);
}

}
14 changes: 14 additions & 0 deletions src/main/resources/dummydata.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#THIS IS A COMMENT.

AAPL, Apple Inc., 276.43
NVID, Nvidida Corporation, 241.591

#Above me are some valid formats.
#Below me are some invalid formats

COOLI, This is a cool name, 252.2

COOL, This is a cool name, 252.2a

AAPL,Apple Inc.,276.43
NVID,Nvidida Corporation,241.591
11 changes: 11 additions & 0 deletions src/main/resources/testStockData.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#THIS IS A COMMENT.

AAPL, Apple Inc., 276.43
NVID, Nvidida Corporation, 241.591

#Above me are some valid formats.
#Below me are some invalid formats

COOLI, This is a cool name, 252.2

COOL, This is a cool name, 252.2a
Loading